Skip to content

Commit d0d6f40

Browse files
committed
Initial commit: Complete Strapi v5 Kubernetes deployment setup
🚀 Features: - Complete K8s manifests for production deployment - Custom Docker image for Strapi v5.18.1 (no official image available) - GitOps-ready configuration for ArgoCD - AWS EKS optimized setup - Multi-environment support (dev/prod) - Automated deployment and verification scripts - Apple Silicon Mac compatibility with Linux builds - Security hardened with secret management - Health checks and monitoring ready - PVC setup for persistent uploads storage 📦 Includes: - Kubernetes manifests (deployment, services, ingress, secrets) - Custom Dockerfile with Node.js 20 Alpine - Automated deploy.sh and verify.sh scripts - Environment configuration templates - Apple Silicon build compatibility warnings - CI/CD validation workflow 🔧 Ready for: - AWS EKS deployment - ArgoCD GitOps workflow - Development and production environments - Custom domain configuration - SSL/TLS termination via ingress
0 parents  commit d0d6f40

27 files changed

+1430
-0
lines changed

.argocd-ignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ArgoCD ignore file
2+
# Place this file in your repository root to prevent ArgoCD from processing documentation files
3+
4+
# Documentation files
5+
*.md
6+
LICENSE
7+
8+
# Development/local files
9+
.git/
10+
.gitignore
11+
.DS_Store
12+
13+
# Node.js dependencies
14+
node_modules/
15+
npm-debug.log*
16+
yarn-debug.log*
17+
yarn-error.log*
18+
package-lock.json
19+
20+
# Optional: Ignore the upgrade directory if you don't want ArgoCD to process it
21+
# strapi-v5-upgrade/

.github/workflows/validate.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: 🧪 Validate YAML Files
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '*.yaml'
7+
- '*.yml'
8+
- 'strapi-v5-upgrade/**/*.yaml'
9+
- 'strapi-v5-upgrade/**/*.yml'
10+
push:
11+
branches: [main, master]
12+
paths:
13+
- '*.yaml'
14+
- '*.yml'
15+
- 'strapi-v5-upgrade/**/*.yaml'
16+
- 'strapi-v5-upgrade/**/*.yml'
17+
18+
jobs:
19+
validate-yaml:
20+
name: 🔍 Validate YAML Syntax
21+
runs-on: ubuntu-latest
22+
23+
steps:
24+
- name: 📥 Checkout code
25+
uses: actions/checkout@v4
26+
27+
- name: 🔧 Setup yamllint
28+
run: pip install yamllint
29+
30+
- name: 🧪 Lint YAML files
31+
run: |
32+
echo "Validating YAML syntax..."
33+
find . -name "*.yaml" -o -name "*.yml" | grep -v ".github" | xargs yamllint -c .yamllint.yaml
34+
35+
- name: ✅ Validate Kubernetes manifests
36+
run: |
37+
echo "Validating Kubernetes manifests..."
38+
# Install kubeval for Kubernetes manifest validation
39+
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz
40+
tar xf kubeval-linux-amd64.tar.gz
41+
sudo mv kubeval /usr/local/bin
42+
43+
# Validate main manifests (skip strapi-secrets.yaml as it has placeholder values)
44+
for file in *.yaml; do
45+
if [[ "$file" != "strapi-secrets.yaml" ]]; then
46+
echo "Validating $file..."
47+
kubeval "$file"
48+
fi
49+
done
50+
51+
validate-dockerfile:
52+
name: 🐳 Validate Dockerfile
53+
runs-on: ubuntu-latest
54+
55+
steps:
56+
- name: 📥 Checkout code
57+
uses: actions/checkout@v4
58+
59+
- name: 🔧 Setup Docker Buildx
60+
uses: docker/setup-buildx-action@v3
61+
62+
- name: 🧪 Build test image
63+
run: |
64+
cd strapi-v5-upgrade
65+
docker buildx build --platform linux/amd64 --dry-run .
66+
67+
validate-scripts:
68+
name: 📜 Validate Shell Scripts
69+
runs-on: ubuntu-latest
70+
71+
steps:
72+
- name: 📥 Checkout code
73+
uses: actions/checkout@v4
74+
75+
- name: 🔧 Setup shellcheck
76+
run: sudo apt-get update && sudo apt-get install -y shellcheck
77+
78+
- name: 🧪 Lint shell scripts
79+
run: |
80+
find . -name "*.sh" -exec shellcheck {} \;
81+
82+
check-secrets:
83+
name: 🔐 Check for Secrets
84+
runs-on: ubuntu-latest
85+
86+
steps:
87+
- name: 📥 Checkout code
88+
uses: actions/checkout@v4
89+
90+
- name: 🔍 Scan for potential secrets
91+
run: |
92+
echo "Checking for potential secrets..."
93+
# Check that strapi-secrets.yaml only contains placeholder values
94+
if grep -q "742561979202\|dev-onair\|172\.16\.1\.152" *.yaml; then
95+
echo "❌ Found non-generic values in YAML files!"
96+
echo "Please ensure all configurations use placeholder values."
97+
exit 1
98+
fi
99+
echo "✅ No hardcoded secrets found"

.yamllint.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extends: default
2+
3+
rules:
4+
line-length:
5+
max: 120
6+
level: warning
7+
comments:
8+
min-spaces-from-content: 1
9+
document-start: disable
10+
truthy:
11+
allowed-values: ['true', 'false', 'on', 'off']
12+
13+
ignore: |
14+
.github/
15+
strapi-v5-upgrade/node_modules/

cm.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
apiVersion: v1
3+
kind: ConfigMap
4+
metadata:
5+
name: strapi-config
6+
namespace: strapi
7+
data:
8+
DATABASE_CLIENT: postgres
9+
DATABASE_HOST: strapi-postgres-postgresql.strapi.svc.cluster.local
10+
DATABASE_PORT: "5432"
11+
DATABASE_NAME: strapi
12+
DATABASE_USERNAME: strapi
13+
HOST: "0.0.0.0"
14+
PORT: "1337"
15+
NODE_ENV: production
16+
# Public URL for proper admin panel access (production server)
17+
PUBLIC_URL: "https://your-domain.com"
18+
# Admin panel URL configuration (production server)
19+
STRAPI_ADMIN_BACKEND_URL: "https://your-domain.com"
20+
ADMIN_PATH: "/admin"
21+
# Strapi v5 specific configurations
22+
STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE: en
23+
# Additional v5 configurations
24+
STRAPI_TELEMETRY_DISABLED: "true"
25+
STRAPI_LOG_LEVEL: "info"
26+
# Vite/Development server configurations
27+
DANGEROUSLY_DISABLE_HOST_CHECK: "true"
28+
VITE_ALLOWED_HOSTS: "all"
29+
VITE_HMR_HOST: "0.0.0.0"
30+
VITE_HMR_PORT: "1337"
31+
# Production CORS and host configuration
32+
TRUSTED_HOSTS: "your-domain.com,private.your-domain.com,localhost,127.0.0.1"
33+
CORS_ORIGIN: "https://your-domain.com,https://private.your-domain.com"
34+
ADMIN_CORS_ORIGIN: "https://your-domain.com,https://private.your-domain.com"
35+

deployment.yaml

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: strapi
5+
namespace: strapi
6+
labels:
7+
app.kubernetes.io/name: strapi
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app.kubernetes.io/name: strapi
13+
template:
14+
metadata:
15+
labels:
16+
app.kubernetes.io/name: strapi
17+
annotations:
18+
kubectl.kubernetes.io/restartedAt: "2025-07-18T18:30:00Z"
19+
spec:
20+
containers:
21+
- name: strapi
22+
image: your-registry/strapi:5-latest
23+
imagePullPolicy: Always
24+
ports:
25+
- containerPort: 1337
26+
name: http
27+
env:
28+
- name: DATABASE_CLIENT
29+
valueFrom:
30+
configMapKeyRef:
31+
name: strapi-config
32+
key: DATABASE_CLIENT
33+
- name: DATABASE_HOST
34+
valueFrom:
35+
configMapKeyRef:
36+
name: strapi-config
37+
key: DATABASE_HOST
38+
- name: DATABASE_PORT
39+
valueFrom:
40+
configMapKeyRef:
41+
name: strapi-config
42+
key: DATABASE_PORT
43+
- name: DATABASE_NAME
44+
valueFrom:
45+
configMapKeyRef:
46+
name: strapi-config
47+
key: DATABASE_NAME
48+
- name: DATABASE_USERNAME
49+
valueFrom:
50+
configMapKeyRef:
51+
name: strapi-config
52+
key: DATABASE_USERNAME
53+
- name: DATABASE_PASSWORD
54+
valueFrom:
55+
secretKeyRef:
56+
name: strapi-postgres-postgresql
57+
key: password # Changed from postgresql-password
58+
- name: HOST
59+
valueFrom:
60+
configMapKeyRef:
61+
name: strapi-config
62+
key: HOST
63+
- name: PORT
64+
valueFrom:
65+
configMapKeyRef:
66+
name: strapi-config
67+
key: PORT
68+
- name: PUBLIC_URL
69+
valueFrom:
70+
configMapKeyRef:
71+
name: strapi-config
72+
key: PUBLIC_URL
73+
- name: NODE_ENV
74+
valueFrom:
75+
configMapKeyRef:
76+
name: strapi-config
77+
key: NODE_ENV
78+
- name: APP_KEYS
79+
valueFrom:
80+
secretKeyRef:
81+
name: strapi-secrets
82+
key: APP_KEYS
83+
- name: API_TOKEN_SALT
84+
valueFrom:
85+
secretKeyRef:
86+
name: strapi-secrets
87+
key: API_TOKEN_SALT
88+
- name: ADMIN_JWT_SECRET
89+
valueFrom:
90+
secretKeyRef:
91+
name: strapi-secrets
92+
key: ADMIN_JWT_SECRET
93+
- name: TRANSFER_TOKEN_SALT
94+
valueFrom:
95+
secretKeyRef:
96+
name: strapi-secrets
97+
key: TRANSFER_TOKEN_SALT
98+
- name: JWT_SECRET
99+
valueFrom:
100+
secretKeyRef:
101+
name: strapi-secrets
102+
key: JWT_SECRET
103+
- name: STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE
104+
valueFrom:
105+
configMapKeyRef:
106+
name: strapi-config
107+
key: STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE
108+
- name: STRAPI_TELEMETRY_DISABLED
109+
valueFrom:
110+
configMapKeyRef:
111+
name: strapi-config
112+
key: STRAPI_TELEMETRY_DISABLED
113+
- name: STRAPI_LOG_LEVEL
114+
valueFrom:
115+
configMapKeyRef:
116+
name: strapi-config
117+
key: STRAPI_LOG_LEVEL
118+
- name: DANGEROUSLY_DISABLE_HOST_CHECK
119+
valueFrom:
120+
configMapKeyRef:
121+
name: strapi-config
122+
key: DANGEROUSLY_DISABLE_HOST_CHECK
123+
- name: VITE_ALLOWED_HOSTS
124+
valueFrom:
125+
configMapKeyRef:
126+
name: strapi-config
127+
key: VITE_ALLOWED_HOSTS
128+
- name: STRAPI_ADMIN_BACKEND_URL
129+
valueFrom:
130+
configMapKeyRef:
131+
name: strapi-config
132+
key: STRAPI_ADMIN_BACKEND_URL
133+
- name: ADMIN_PATH
134+
valueFrom:
135+
configMapKeyRef:
136+
name: strapi-config
137+
key: ADMIN_PATH
138+
- name: VITE_HMR_HOST
139+
valueFrom:
140+
configMapKeyRef:
141+
name: strapi-config
142+
key: VITE_HMR_HOST
143+
- name: VITE_HMR_PORT
144+
valueFrom:
145+
configMapKeyRef:
146+
name: strapi-config
147+
key: VITE_HMR_PORT
148+
- name: STRAPI_DISABLE_UPDATE_NOTIFICATION
149+
value: "true"
150+
- name: STRAPI_HIDE_STARTUP_MESSAGE
151+
value: "true"
152+
- name: NODE_OPTIONS
153+
value: "--max-old-space-size=4096"
154+
command: ["yarn", "start"]
155+
args: []
156+
resources:
157+
requests:
158+
cpu: "500m"
159+
memory: "2Gi"
160+
limits:
161+
cpu: "2"
162+
memory: "6Gi"
163+
volumeMounts:
164+
- name: strapi-data
165+
mountPath: /opt/app/data
166+
- name: strapi-uploads
167+
mountPath: /opt/app/public/uploads
168+
- name: strapi-data
169+
mountPath: /opt/app/src/api
170+
subPath: src-api
171+
- name: strapi-data
172+
mountPath: /opt/app/.strapi
173+
subPath: strapi-metadata
174+
- name: strapi-data
175+
mountPath: /opt/app/src
176+
subPath: src
177+
- name: vite-config
178+
mountPath: /opt/app/vite.config.admin.js
179+
subPath: vite.config.admin.js
180+
livenessProbe:
181+
httpGet:
182+
path: /_health
183+
port: http
184+
initialDelaySeconds: 60
185+
periodSeconds: 10
186+
timeoutSeconds: 5
187+
readinessProbe:
188+
httpGet:
189+
path: /_health
190+
port: http
191+
initialDelaySeconds: 60
192+
periodSeconds: 10
193+
timeoutSeconds: 5
194+
volumes:
195+
- name: strapi-data
196+
persistentVolumeClaim:
197+
claimName: strapi-data
198+
- name: strapi-uploads
199+
persistentVolumeClaim:
200+
claimName: strapi-uploads
201+
- name: vite-config
202+
configMap:
203+
name: strapi-vite-config
204+
securityContext:
205+
runAsUser: 1001
206+
fsGroup: 1001
207+
affinity:
208+
podAntiAffinity:
209+
preferredDuringSchedulingIgnoredDuringExecution:
210+
- weight: 1
211+
podAffinityTerm:
212+
labelSelector:
213+
matchLabels:
214+
app.kubernetes.io/name: strapi
215+
topologyKey: kubernetes.io/hostname

0 commit comments

Comments
 (0)