Files
2025-11-29 18:48:00 +08:00

725 lines
14 KiB
Markdown

# Deploy Application Command
You are helping the user deploy their application to various platforms and orchestrators following Sngular's deployment best practices.
## Instructions
1. **Determine deployment target**:
- Kubernetes (K8s)
- Docker Swarm
- AWS (ECS, EKS, EC2, Lambda)
- Google Cloud (GKE, Cloud Run, App Engine)
- Azure (AKS, Container Instances, App Service)
- Vercel / Netlify (for frontend)
- Heroku
- DigitalOcean
- Railway
2. **Identify application type**:
- Containerized application (Docker)
- Serverless function
- Static site
- Full-stack application
- Microservices
3. **Ask about requirements**:
- Environment (staging, production)
- Scaling needs (replicas, auto-scaling)
- Resource limits (CPU, memory)
- Database / persistent storage
- Load balancing
- SSL/TLS certificates
- Domain configuration
- Monitoring and logging
## Kubernetes Deployment
### Deployment Configuration
```yaml
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
labels:
app: myapp
version: v1.0.0
spec:
replicas: 3
revisionHistoryLimit: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
version: v1.0.0
spec:
# Security
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
# Init containers (migrations, etc.)
initContainers:
- name: migrate
image: myapp:latest
command: ['npm', 'run', 'migrate']
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: myapp-secrets
key: database-url
containers:
- name: myapp
image: myapp:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 3000
protocol: TCP
# Environment variables
env:
- name: NODE_ENV
value: production
- name: PORT
value: "3000"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: myapp-secrets
key: database-url
- name: REDIS_URL
valueFrom:
configMapKeyRef:
name: myapp-config
key: redis-url
# Resource limits
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# Health checks
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Startup probe for slow-starting apps
startupProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 30
# Volume mounts
volumeMounts:
- name: app-config
mountPath: /app/config
readOnly: true
volumes:
- name: app-config
configMap:
name: myapp-config
# Image pull secrets
imagePullSecrets:
- name: registry-credentials
```
### Service Configuration
```yaml
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: production
labels:
app: myapp
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: myapp
```
### Ingress Configuration
```yaml
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: production
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
```
### ConfigMap and Secrets
```yaml
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: production
data:
redis-url: "redis://redis-service:6379"
log-level: "info"
feature-flag-enabled: "true"
```
```yaml
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: production
type: Opaque
data:
# Base64 encoded values
database-url: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0BkYjoxMjM0NS9teWFwcA==
jwt-secret: c3VwZXJzZWNyZXRrZXk=
```
### Horizontal Pod Autoscaler
```yaml
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
```
### Namespace Configuration
```yaml
# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
name: production
environment: production
```
## Helm Chart
```yaml
# Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 1.0.0
appVersion: "1.0.0"
```
```yaml
# values.yaml
replicaCount: 3
image:
repository: myapp
pullPolicy: Always
tag: "latest"
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
env:
NODE_ENV: production
PORT: "3000"
secrets:
DATABASE_URL: ""
JWT_SECRET: ""
```
## Docker Compose Deployment
```yaml
# docker-compose.prod.yml
version: '3.8'
services:
app:
image: myapp:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: ${DATABASE_URL}
REDIS_URL: redis://redis:6379
depends_on:
- db
- redis
networks:
- app-network
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
max_attempts: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: myapp
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
postgres_data:
```
## AWS Deployment
### ECS Task Definition
```json
{
"family": "myapp",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "myapp",
"image": "123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/database-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
}
]
}
```
### Lambda Function (Serverless)
```yaml
# serverless.yml
service: myapp
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
stage: ${opt:stage, 'dev'}
environment:
NODE_ENV: ${self:provider.stage}
DATABASE_URL: ${env:DATABASE_URL}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
Resource: "arn:aws:dynamodb:*:*:table/MyTable"
functions:
api:
handler: dist/lambda.handler
events:
- http:
path: /{proxy+}
method: ANY
cors: true
timeout: 30
memorySize: 512
scheduled:
handler: dist/scheduled.handler
events:
- schedule: rate(1 hour)
plugins:
- serverless-plugin-typescript
- serverless-offline
package:
individually: true
patterns:
- '!node_modules/**'
- '!src/**'
- 'dist/**'
```
## Vercel Deployment (Frontend)
```json
// vercel.json
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"routes": [
{
"src": "/api/(.*)",
"dest": "/api/$1"
}
],
"env": {
"NODE_ENV": "production",
"NEXT_PUBLIC_API_URL": "@api_url"
},
"regions": ["iad1"],
"github": {
"enabled": true,
"autoAlias": true,
"silent": true
}
}
```
## Deployment Scripts
### Rolling Update Script
```bash
#!/bin/bash
# deploy.sh
set -e
ENVIRONMENT=${1:-staging}
IMAGE_TAG=${2:-latest}
echo "Deploying to $ENVIRONMENT with image tag $IMAGE_TAG"
# Update Kubernetes deployment
kubectl set image deployment/myapp \
myapp=myapp:$IMAGE_TAG \
--namespace=$ENVIRONMENT \
--record
# Wait for rollout to complete
kubectl rollout status deployment/myapp \
--namespace=$ENVIRONMENT \
--timeout=5m
# Verify deployment
kubectl get pods \
--namespace=$ENVIRONMENT \
--selector=app=myapp
echo "Deployment completed successfully!"
```
### Blue-Green Deployment
```bash
#!/bin/bash
# blue-green-deploy.sh
set -e
NAMESPACE="production"
NEW_VERSION=$1
CURRENT_SERVICE=$(kubectl get service myapp -n $NAMESPACE -o jsonpath='{.spec.selector.version}')
echo "Current version: $CURRENT_SERVICE"
echo "New version: $NEW_VERSION"
# Deploy new version (green)
kubectl apply -f k8s/deployment-$NEW_VERSION.yaml -n $NAMESPACE
# Wait for new version to be ready
kubectl wait --for=condition=available --timeout=300s \
deployment/myapp-$NEW_VERSION -n $NAMESPACE
# Run smoke tests
if ! ./scripts/smoke-test.sh http://myapp-$NEW_VERSION:80; then
echo "Smoke tests failed! Rolling back..."
kubectl delete deployment/myapp-$NEW_VERSION -n $NAMESPACE
exit 1
fi
# Switch traffic to new version
kubectl patch service myapp -n $NAMESPACE \
-p '{"spec":{"selector":{"version":"'$NEW_VERSION'"}}}'
echo "Traffic switched to $NEW_VERSION"
# Wait and monitor
sleep 60
# Delete old version
if [ "$CURRENT_SERVICE" != "" ]; then
kubectl delete deployment/myapp-$CURRENT_SERVICE -n $NAMESPACE
echo "Old version $CURRENT_SERVICE deleted"
fi
echo "Blue-green deployment completed!"
```
### Health Check Script
```bash
#!/bin/bash
# health-check.sh
URL=$1
MAX_ATTEMPTS=30
SLEEP_TIME=10
for i in $(seq 1 $MAX_ATTEMPTS); do
echo "Attempt $i of $MAX_ATTEMPTS"
if curl -f -s $URL/health > /dev/null; then
echo "Health check passed!"
exit 0
fi
if [ $i -lt $MAX_ATTEMPTS ]; then
echo "Health check failed, retrying in $SLEEP_TIME seconds..."
sleep $SLEEP_TIME
fi
done
echo "Health check failed after $MAX_ATTEMPTS attempts"
exit 1
```
## Best Practices
### Security
- Use secrets management (never commit secrets)
- Enable RBAC in Kubernetes
- Use network policies to restrict traffic
- Scan images for vulnerabilities
- Run containers as non-root
- Use read-only root filesystem where possible
- Enable pod security policies
### Reliability
- Set appropriate resource limits
- Configure health checks (liveness, readiness)
- Use rolling updates with maxUnavailable: 0
- Implement circuit breakers
- Set up autoscaling
- Configure pod disruption budgets
- Use multiple replicas across zones
### Monitoring
- Set up logging (ELK, Loki, CloudWatch)
- Configure metrics (Prometheus, Datadog)
- Set up alerts for critical issues
- Use distributed tracing (Jaeger, Zipkin)
- Monitor resource usage
- Track deployment success/failure rates
### Performance
- Use CDN for static assets
- Enable caching where appropriate
- Optimize container images
- Use horizontal pod autoscaling
- Configure connection pooling
- Implement rate limiting
Ask the user: "What platform would you like to deploy to?"