fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
887
deployment/docs/DEPLOYMENT_GUIDE.md
Normal file
887
deployment/docs/DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,887 @@
|
||||
# SSH Deployment Guide
|
||||
|
||||
Comprehensive guide for deploying the Custom PHP Framework using SSH-based deployment scripts.
|
||||
|
||||
## Overview
|
||||
|
||||
This deployment system uses simple SSH/SCP-based scripts to deploy the framework to staging and production environments. It replaces Gitea Actions with a straightforward bash script approach.
|
||||
|
||||
**Key Features**:
|
||||
- ✅ Simple SSH/SCP deployment (no CI/CD platform dependency)
|
||||
- ✅ Automatic Docker image building and registry pushing
|
||||
- ✅ Database backups before production deployments
|
||||
- ✅ Automatic rollback on deployment failure
|
||||
- ✅ Health checks and smoke tests
|
||||
- ✅ Timestamped backup retention
|
||||
- ✅ Color-coded output for easy monitoring
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Software
|
||||
|
||||
**Local Machine**:
|
||||
- Docker (for building images)
|
||||
- Docker Compose (for compose file validation)
|
||||
- SSH client (openssh-client)
|
||||
- SCP client (usually bundled with SSH)
|
||||
- Bash shell
|
||||
|
||||
**Remote Servers** (staging/production):
|
||||
- Docker and Docker Compose installed
|
||||
- SSH server running
|
||||
- Docker private registry accessible (localhost:5000 or custom)
|
||||
- Deployment user with Docker permissions
|
||||
- Directory structure: `/opt/framework-staging/` or `/opt/framework-production/`
|
||||
|
||||
### SSH Key Setup
|
||||
|
||||
Generate SSH keys for deployment (if not already done):
|
||||
|
||||
```bash
|
||||
# Generate deployment SSH key
|
||||
ssh-keygen -t rsa -b 4096 -f ~/.ssh/framework-deploy \
|
||||
-C "framework-deployment" -N ""
|
||||
|
||||
# Copy public key to staging server
|
||||
ssh-copy-id -i ~/.ssh/framework-deploy.pub deploy@staging.michaelschiemer.de
|
||||
|
||||
# Copy public key to production server
|
||||
ssh-copy-id -i ~/.ssh/framework-deploy.pub deploy@michaelschiemer.de
|
||||
|
||||
# Test connection
|
||||
ssh -i ~/.ssh/framework-deploy deploy@staging.michaelschiemer.de "echo 'SSH connection successful'"
|
||||
```
|
||||
|
||||
**SSH Config** (~/.ssh/config):
|
||||
```
|
||||
# Staging Server
|
||||
Host staging.michaelschiemer.de
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/framework-deploy
|
||||
Port 22
|
||||
|
||||
# Production Server
|
||||
Host michaelschiemer.de
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/framework-deploy
|
||||
Port 22
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
**Staging Deployment**:
|
||||
```bash
|
||||
export STAGING_HOST=staging.michaelschiemer.de
|
||||
export STAGING_USER=deploy
|
||||
export STAGING_SSH_PORT=22
|
||||
```
|
||||
|
||||
**Production Deployment**:
|
||||
```bash
|
||||
export PRODUCTION_HOST=michaelschiemer.de
|
||||
export PRODUCTION_USER=deploy
|
||||
export PRODUCTION_SSH_PORT=22
|
||||
```
|
||||
|
||||
**Optional Configuration**:
|
||||
```bash
|
||||
# Docker Registry (default: localhost:5000)
|
||||
export REGISTRY=your-registry.com
|
||||
|
||||
# Image Configuration
|
||||
export IMAGE_NAME=framework
|
||||
export IMAGE_TAG=latest # or staging
|
||||
|
||||
# Production Options
|
||||
export SKIP_BACKUP=false # Skip database backup (not recommended)
|
||||
export FORCE_REBUILD=false # Force Docker rebuild
|
||||
```
|
||||
|
||||
**Persistent Configuration** (.bashrc or .zshrc):
|
||||
```bash
|
||||
# Add to ~/.bashrc or ~/.zshrc
|
||||
export STAGING_HOST=staging.michaelschiemer.de
|
||||
export STAGING_USER=deploy
|
||||
export PRODUCTION_HOST=michaelschiemer.de
|
||||
export PRODUCTION_USER=deploy
|
||||
```
|
||||
|
||||
## Deployment Scripts
|
||||
|
||||
### 1. Staging Deployment
|
||||
|
||||
**Script**: `deployment/scripts/deploy-staging.sh`
|
||||
|
||||
**Purpose**: Deploy to staging environment for testing
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Basic deployment
|
||||
./deployment/scripts/deploy-staging.sh
|
||||
|
||||
# With custom configuration
|
||||
STAGING_HOST=custom.staging.com ./deployment/scripts/deploy-staging.sh
|
||||
```
|
||||
|
||||
**What It Does**:
|
||||
1. Builds Docker image with `ENV=staging`
|
||||
2. Pushes image to private registry
|
||||
3. Creates timestamped backup of current deployment
|
||||
4. Copies deployment files via SCP
|
||||
5. Stops existing containers
|
||||
6. Starts new containers
|
||||
7. Waits 30 seconds for services to initialize
|
||||
8. Performs health checks
|
||||
9. Automatic rollback on failure
|
||||
|
||||
**Backup Retention**: Keeps last 5 backups, deletes older
|
||||
|
||||
**Deployment Path**: `/opt/framework-staging/current/`
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
==================================================
|
||||
🚀 Starting Staging Deployment
|
||||
==================================================
|
||||
Registry: localhost:5000
|
||||
Image: framework:staging
|
||||
Remote: deploy@staging.michaelschiemer.de:22
|
||||
Path: /opt/framework-staging
|
||||
|
||||
[1/7] Building Docker image...
|
||||
[2/7] Pushing image to registry...
|
||||
[3/7] Preparing deployment files...
|
||||
[4/7] Creating remote directory and backup...
|
||||
Backing up current deployment...
|
||||
Backup created: backup_20250124_153022
|
||||
[5/7] Copying deployment files to server...
|
||||
[6/7] Executing deployment on server...
|
||||
==================================================
|
||||
Starting Staging Deployment on Server
|
||||
==================================================
|
||||
[1/5] Pulling latest Docker images...
|
||||
[2/5] Stopping existing containers...
|
||||
[3/5] Starting new containers...
|
||||
[4/5] Waiting for services to be healthy...
|
||||
[5/5] Verifying deployment...
|
||||
==================================================
|
||||
✅ Staging Deployment Complete
|
||||
==================================================
|
||||
[7/7] Performing health checks...
|
||||
Waiting 30 seconds for services to initialize...
|
||||
Checking container status...
|
||||
✅ Health check complete!
|
||||
|
||||
==================================================
|
||||
✅ Staging Deployment Successful
|
||||
==================================================
|
||||
URL: https://staging.michaelschiemer.de
|
||||
Deployed at: Thu Jan 24 15:30:45 CET 2025
|
||||
```
|
||||
|
||||
### 2. Production Deployment
|
||||
|
||||
**Script**: `deployment/scripts/deploy-production.sh`
|
||||
|
||||
**Purpose**: Deploy to production environment
|
||||
|
||||
**⚠️ WARNING**: Production deployments include:
|
||||
- Automatic database backup (mandatory unless skipped)
|
||||
- 60-second service initialization wait
|
||||
- Smoke tests for main page and API health
|
||||
- Automatic rollback on any failure
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Standard production deployment
|
||||
./deployment/scripts/deploy-production.sh
|
||||
|
||||
# Skip database backup (NOT RECOMMENDED)
|
||||
SKIP_BACKUP=true ./deployment/scripts/deploy-production.sh
|
||||
|
||||
# Force Docker rebuild
|
||||
FORCE_REBUILD=true ./deployment/scripts/deploy-production.sh
|
||||
```
|
||||
|
||||
**What It Does**:
|
||||
1. Builds Docker image with `ENV=production`
|
||||
2. Pushes image to private registry
|
||||
3. **Creates database backup** (aborts if backup fails)
|
||||
4. Creates timestamped backup of current deployment
|
||||
5. Copies deployment files via SCP
|
||||
6. Stops existing containers gracefully
|
||||
7. Starts new containers
|
||||
8. Waits 60 seconds for services to initialize
|
||||
9. Runs database migrations with `--force`
|
||||
10. Performs comprehensive health checks:
|
||||
- Container status
|
||||
- PHP-FPM process check
|
||||
- Redis connection test
|
||||
11. **Runs smoke tests**:
|
||||
- Main page accessibility (https://michaelschiemer.de/)
|
||||
- API health endpoint (https://michaelschiemer.de/api/health)
|
||||
12. Automatic rollback on any failure
|
||||
|
||||
**Backup Retention**: Keeps last 10 backups, deletes older
|
||||
|
||||
**Deployment Path**: `/opt/framework-production/current/`
|
||||
|
||||
**Database Backup Location**: `/var/www/html/storage/backups/backup_YYYYMMDD_HHMMSS.sql`
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
==================================================
|
||||
🚀 Starting Production Deployment
|
||||
==================================================
|
||||
Registry: localhost:5000
|
||||
Image: framework:latest
|
||||
Remote: deploy@michaelschiemer.de:22
|
||||
Path: /opt/framework-production
|
||||
Skip Backup: false
|
||||
|
||||
[1/8] Building Docker image...
|
||||
[2/8] Pushing image to registry...
|
||||
[3/8] Preparing deployment files...
|
||||
[4/8] Creating remote directory and backup...
|
||||
[5/8] Copying deployment files to server...
|
||||
[6/8] Executing deployment on server...
|
||||
==================================================
|
||||
Starting Production Deployment on Server
|
||||
==================================================
|
||||
[0/6] Creating database backup...
|
||||
✅ Database backup created: backup_20250124_153045.sql
|
||||
[1/6] Pulling latest Docker images...
|
||||
[2/6] Stopping existing containers (graceful shutdown)...
|
||||
[3/6] Starting new containers...
|
||||
[4/6] Waiting for services to be healthy...
|
||||
[5/6] Running database migrations...
|
||||
[6/6] Verifying deployment...
|
||||
==================================================
|
||||
✅ Production Deployment Complete
|
||||
==================================================
|
||||
[7/8] Performing health checks...
|
||||
Waiting 60 seconds for services to initialize...
|
||||
Checking container status...
|
||||
✅ All health checks passed!
|
||||
[8/8] Running smoke tests...
|
||||
✅ Main page accessible
|
||||
✅ API health check passed
|
||||
✅ Smoke tests completed successfully
|
||||
|
||||
==================================================
|
||||
✅ Production Deployment Successful
|
||||
==================================================
|
||||
URL: https://michaelschiemer.de
|
||||
Deployed at: Thu Jan 24 15:32:15 CET 2025
|
||||
```
|
||||
|
||||
### 3. Rollback Script
|
||||
|
||||
**Script**: `deployment/scripts/rollback.sh`
|
||||
|
||||
**Purpose**: Restore previous deployment from backup
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Rollback staging to latest backup
|
||||
./deployment/scripts/rollback.sh staging
|
||||
|
||||
# Rollback production to latest backup
|
||||
./deployment/scripts/rollback.sh production
|
||||
|
||||
# Rollback to specific backup
|
||||
./deployment/scripts/rollback.sh production backup_20250124_143022
|
||||
```
|
||||
|
||||
**What It Does**:
|
||||
1. Lists available backups
|
||||
2. Confirms rollback operation (requires "yes")
|
||||
3. Stops current deployment
|
||||
4. Archives failed deployment as `failed_YYYYMMDD_HHMMSS`
|
||||
5. Restores specified backup
|
||||
6. Starts restored deployment
|
||||
7. Performs health checks
|
||||
|
||||
**Arguments**:
|
||||
- `environment`: `staging` or `production` (required)
|
||||
- `backup_name`: Specific backup to restore (optional, defaults to latest)
|
||||
|
||||
**Example Session**:
|
||||
```bash
|
||||
$ ./deployment/scripts/rollback.sh production
|
||||
|
||||
==================================================
|
||||
🔄 Starting Rollback: production
|
||||
==================================================
|
||||
Remote: deploy@michaelschiemer.de:22
|
||||
Path: /opt/framework-production
|
||||
Target Backup: Latest available
|
||||
|
||||
⚠️ WARNING: This will rollback the production deployment
|
||||
Current deployment will be stopped and replaced with backup
|
||||
|
||||
Are you sure you want to continue? (yes/no): yes
|
||||
|
||||
[1/5] Listing available backups...
|
||||
Available backups:
|
||||
backup_20250124_153045
|
||||
backup_20250124_120000
|
||||
backup_20250123_183015
|
||||
|
||||
[2/5] Determining backup to restore...
|
||||
Using latest backup: backup_20250124_153045
|
||||
✅ Backup backup_20250124_153045 verified
|
||||
|
||||
[3/5] Stopping current deployment...
|
||||
✅ Current deployment stopped
|
||||
|
||||
[4/5] Restoring backup...
|
||||
Archiving failed deployment as failed_20250124_154512...
|
||||
Restoring backup backup_20250124_153045...
|
||||
✅ Backup restored
|
||||
|
||||
[5/5] Starting restored deployment...
|
||||
Starting containers...
|
||||
Waiting for services to start...
|
||||
✅ Restored deployment is running
|
||||
|
||||
==================================================
|
||||
✅ Rollback Complete
|
||||
==================================================
|
||||
Environment: production
|
||||
Restored: backup_20250124_153045
|
||||
Completed at: Thu Jan 24 15:45:30 CET 2025
|
||||
|
||||
Failed deployment archived as: failed_20250124_154512
|
||||
```
|
||||
|
||||
## Deployment Workflows
|
||||
|
||||
### Staging Deployment Workflow
|
||||
|
||||
**Step-by-Step Process**:
|
||||
|
||||
1. **Prepare Changes**:
|
||||
```bash
|
||||
# Make code changes locally
|
||||
git add .
|
||||
git commit -m "feat: new feature"
|
||||
git push origin staging
|
||||
```
|
||||
|
||||
2. **Deploy to Staging**:
|
||||
```bash
|
||||
# Set environment variables (if not in ~/.bashrc)
|
||||
export STAGING_HOST=staging.michaelschiemer.de
|
||||
export STAGING_USER=deploy
|
||||
|
||||
# Run deployment
|
||||
./deployment/scripts/deploy-staging.sh
|
||||
```
|
||||
|
||||
3. **Verify Deployment**:
|
||||
```bash
|
||||
# Check application
|
||||
curl -k https://staging.michaelschiemer.de/health
|
||||
|
||||
# Monitor logs
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && docker-compose logs -f"
|
||||
|
||||
# Check container status
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && docker-compose ps"
|
||||
```
|
||||
|
||||
4. **Test Application**:
|
||||
- Perform manual testing
|
||||
- Run automated tests
|
||||
- Verify feature functionality
|
||||
- Check performance
|
||||
|
||||
5. **If Issues Found**:
|
||||
```bash
|
||||
# Rollback staging
|
||||
./deployment/scripts/rollback.sh staging
|
||||
|
||||
# Or continue testing for non-critical issues
|
||||
```
|
||||
|
||||
### Production Deployment Workflow
|
||||
|
||||
**Step-by-Step Process**:
|
||||
|
||||
1. **Pre-Deployment Checklist**:
|
||||
- [ ] Code reviewed and approved
|
||||
- [ ] Successfully deployed and tested in staging
|
||||
- [ ] Database migrations tested
|
||||
- [ ] Backup plan confirmed
|
||||
- [ ] Rollback plan confirmed
|
||||
- [ ] Team notified of deployment window
|
||||
|
||||
2. **Prepare Production Branch**:
|
||||
```bash
|
||||
# Merge staging to main
|
||||
git checkout main
|
||||
git merge staging
|
||||
git push origin main
|
||||
```
|
||||
|
||||
3. **Verify Environment Variables**:
|
||||
```bash
|
||||
# Required variables
|
||||
echo $PRODUCTION_HOST # Should be: michaelschiemer.de
|
||||
echo $PRODUCTION_USER # Should be: deploy
|
||||
|
||||
# If not set
|
||||
export PRODUCTION_HOST=michaelschiemer.de
|
||||
export PRODUCTION_USER=deploy
|
||||
```
|
||||
|
||||
4. **Deploy to Production**:
|
||||
```bash
|
||||
# IMPORTANT: Do NOT skip database backup
|
||||
./deployment/scripts/deploy-production.sh
|
||||
|
||||
# Monitor output carefully for any errors
|
||||
```
|
||||
|
||||
5. **Post-Deployment Verification**:
|
||||
```bash
|
||||
# 1. Check main application
|
||||
curl -k https://michaelschiemer.de/
|
||||
|
||||
# 2. Check API health
|
||||
curl -k https://michaelschiemer.de/api/health
|
||||
|
||||
# 3. Monitor logs for errors
|
||||
ssh deploy@michaelschiemer.de \
|
||||
"cd /opt/framework-production/current && docker-compose logs -f --tail=100"
|
||||
|
||||
# 4. Check container status
|
||||
ssh deploy@michaelschiemer.de \
|
||||
"cd /opt/framework-production/current && docker-compose ps"
|
||||
|
||||
# 5. Verify database migrations applied
|
||||
ssh deploy@michaelschiemer.de \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose exec production-app php console.php db:status"
|
||||
```
|
||||
|
||||
6. **Smoke Testing**:
|
||||
- Test critical user paths
|
||||
- Verify authentication
|
||||
- Test key API endpoints
|
||||
- Check database connectivity
|
||||
- Verify external integrations
|
||||
|
||||
7. **If Deployment Fails**:
|
||||
```bash
|
||||
# Automatic rollback should have occurred
|
||||
# If manual rollback needed:
|
||||
./deployment/scripts/rollback.sh production
|
||||
|
||||
# Monitor rollback
|
||||
ssh deploy@michaelschiemer.de \
|
||||
"cd /opt/framework-production/current && docker-compose logs -f"
|
||||
```
|
||||
|
||||
8. **Post-Deployment**:
|
||||
- Monitor application metrics
|
||||
- Watch error logs for 30 minutes
|
||||
- Notify team of successful deployment
|
||||
- Document any issues encountered
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### SSH Connection Issues
|
||||
|
||||
**Problem**: `Permission denied (publickey)`
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Verify SSH key exists
|
||||
ls -la ~/.ssh/framework-deploy*
|
||||
|
||||
# Test SSH connection
|
||||
ssh -i ~/.ssh/framework-deploy deploy@staging.michaelschiemer.de "echo 'SSH works'"
|
||||
|
||||
# Check SSH config
|
||||
cat ~/.ssh/config
|
||||
|
||||
# Re-copy public key
|
||||
ssh-copy-id -i ~/.ssh/framework-deploy.pub deploy@staging.michaelschiemer.de
|
||||
|
||||
# Check server-side authorized_keys
|
||||
ssh deploy@staging.michaelschiemer.de "cat ~/.ssh/authorized_keys"
|
||||
```
|
||||
|
||||
### Docker Build Failures
|
||||
|
||||
**Problem**: Docker build fails during deployment
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Check Docker is running
|
||||
docker info
|
||||
|
||||
# Test build locally
|
||||
docker build \
|
||||
--file docker/php/Dockerfile \
|
||||
--tag localhost:5000/framework:test \
|
||||
--build-arg ENV=staging \
|
||||
.
|
||||
|
||||
# Check Dockerfile syntax
|
||||
docker build --file docker/php/Dockerfile --no-cache .
|
||||
|
||||
# Clear Docker cache
|
||||
docker system prune -a
|
||||
```
|
||||
|
||||
### Registry Push Failures
|
||||
|
||||
**Problem**: `docker push` fails
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Check registry is accessible
|
||||
curl http://localhost:5000/v2/
|
||||
|
||||
# Verify image exists locally
|
||||
docker images | grep framework
|
||||
|
||||
# Test manual push
|
||||
docker push localhost:5000/framework:staging
|
||||
|
||||
# Check registry logs
|
||||
docker logs registry # If running registry as container
|
||||
```
|
||||
|
||||
### Deployment Script Fails
|
||||
|
||||
**Problem**: Deployment script exits with error
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Run with bash debug mode
|
||||
bash -x ./deployment/scripts/deploy-staging.sh
|
||||
|
||||
# Check remote directory exists
|
||||
ssh deploy@staging.michaelschiemer.de "ls -la /opt/framework-staging"
|
||||
|
||||
# Verify Docker Compose files
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && docker-compose config"
|
||||
|
||||
# Check deployment logs on server
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && docker-compose logs"
|
||||
```
|
||||
|
||||
### Health Check Failures
|
||||
|
||||
**Problem**: Health checks fail but containers are running
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Check container logs
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && docker-compose logs --tail=50"
|
||||
|
||||
# Check PHP-FPM status
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && \
|
||||
docker-compose exec staging-app pgrep php-fpm"
|
||||
|
||||
# Test health endpoint manually
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"curl -k http://localhost/health"
|
||||
|
||||
# Check Nginx configuration
|
||||
ssh deploy@staging.michaelschiemer.de \
|
||||
"cd /opt/framework-staging/current && \
|
||||
docker-compose exec staging-nginx nginx -t"
|
||||
```
|
||||
|
||||
### Rollback Issues
|
||||
|
||||
**Problem**: Rollback script fails
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# List available backups
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production && ls -dt backup_*"
|
||||
|
||||
# Manually restore backup
|
||||
ssh deploy@production "
|
||||
cd /opt/framework-production
|
||||
docker-compose -f current/docker-compose.base.yml \
|
||||
-f current/docker-compose.prod.yml down
|
||||
rm -rf current
|
||||
cp -r backup_20250124_153045 current
|
||||
cd current
|
||||
docker-compose -f docker-compose.base.yml \
|
||||
-f docker-compose.prod.yml up -d
|
||||
"
|
||||
|
||||
# Check failed deployment archive
|
||||
ssh deploy@production "ls -dt /opt/framework-production/failed_*"
|
||||
```
|
||||
|
||||
### Database Migration Failures
|
||||
|
||||
**Problem**: Migrations fail during deployment
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Check migration status
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose exec production-app php console.php db:status"
|
||||
|
||||
# Manually run migrations
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose exec production-app php console.php db:migrate --force"
|
||||
|
||||
# Rollback migrations
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose exec production-app php console.php db:rollback"
|
||||
|
||||
# Check database connectivity
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose exec production-app php console.php db:check"
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### SSH Key Management
|
||||
|
||||
**✅ Do**:
|
||||
- Use 4096-bit RSA keys minimum
|
||||
- Generate separate keys for staging and production
|
||||
- Store private keys securely (never commit to git)
|
||||
- Rotate keys quarterly
|
||||
- Use SSH config for key management
|
||||
|
||||
**❌ Don't**:
|
||||
- Use password-only authentication
|
||||
- Share keys between environments
|
||||
- Commit private keys to version control
|
||||
- Use personal SSH keys for deployments
|
||||
|
||||
### Environment Variables
|
||||
|
||||
**✅ Do**:
|
||||
- Use environment variables for secrets
|
||||
- Document required variables
|
||||
- Use different credentials per environment
|
||||
- Validate variables before deployment
|
||||
|
||||
**❌ Don't**:
|
||||
- Hard-code credentials in scripts
|
||||
- Commit .env files with secrets
|
||||
- Use production credentials in staging
|
||||
|
||||
### Deployment User Permissions
|
||||
|
||||
**Recommended Setup**:
|
||||
```bash
|
||||
# On remote server
|
||||
# Create deployment user
|
||||
sudo useradd -m -s /bin/bash deploy
|
||||
|
||||
# Add to docker group
|
||||
sudo usermod -aG docker deploy
|
||||
|
||||
# Set directory ownership
|
||||
sudo chown -R deploy:deploy /opt/framework-staging
|
||||
sudo chown -R deploy:deploy /opt/framework-production
|
||||
|
||||
# Restrict sudo (if needed)
|
||||
# Add to /etc/sudoers.d/deploy
|
||||
deploy ALL=(ALL) NOPASSWD: /usr/bin/docker, /usr/bin/docker-compose
|
||||
```
|
||||
|
||||
### Backup Management
|
||||
|
||||
**✅ Do**:
|
||||
- Automate database backups
|
||||
- Keep multiple backup versions
|
||||
- Test backup restoration regularly
|
||||
- Monitor backup disk space
|
||||
|
||||
**❌ Don't**:
|
||||
- Skip backups in production
|
||||
- Keep unlimited backups (disk space)
|
||||
- Store backups only on deployment server
|
||||
|
||||
## Monitoring and Maintenance
|
||||
|
||||
### Health Monitoring
|
||||
|
||||
**Automated Checks**:
|
||||
```bash
|
||||
# Cron job for health monitoring
|
||||
# Add to crontab -e on deployment server
|
||||
*/5 * * * * curl -f -k https://michaelschiemer.de/health || echo "Health check failed" | mail -s "Production Health Alert" admin@michaelschiemer.de
|
||||
```
|
||||
|
||||
**Manual Checks**:
|
||||
```bash
|
||||
# Check all services
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && docker-compose ps"
|
||||
|
||||
# Check resource usage
|
||||
ssh deploy@production "docker stats --no-stream"
|
||||
|
||||
# Check disk space
|
||||
ssh deploy@production "df -h /opt/framework-production"
|
||||
```
|
||||
|
||||
### Log Management
|
||||
|
||||
**View Logs**:
|
||||
```bash
|
||||
# Follow logs
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && docker-compose logs -f"
|
||||
|
||||
# View specific service logs
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose logs -f production-app"
|
||||
|
||||
# Last 100 lines
|
||||
ssh deploy@production \
|
||||
"cd /opt/framework-production/current && \
|
||||
docker-compose logs --tail=100"
|
||||
```
|
||||
|
||||
### Backup Cleanup
|
||||
|
||||
**Manual Cleanup**:
|
||||
```bash
|
||||
# List backups by size
|
||||
ssh deploy@production "du -sh /opt/framework-production/backup_* | sort -h"
|
||||
|
||||
# Remove specific old backup
|
||||
ssh deploy@production "rm -rf /opt/framework-production/backup_20240101_000000"
|
||||
|
||||
# Keep only last 5 backups
|
||||
ssh deploy@staging "
|
||||
cd /opt/framework-staging
|
||||
ls -dt backup_* | tail -n +6 | xargs rm -rf
|
||||
"
|
||||
```
|
||||
|
||||
## Appendix
|
||||
|
||||
### Directory Structure
|
||||
|
||||
**Local Project**:
|
||||
```
|
||||
michaelschiemer/
|
||||
├── deployment/
|
||||
│ ├── scripts/
|
||||
│ │ ├── deploy-staging.sh # Staging deployment
|
||||
│ │ ├── deploy-production.sh # Production deployment
|
||||
│ │ └── rollback.sh # Rollback script
|
||||
│ ├── docs/
|
||||
│ │ └── DEPLOYMENT_GUIDE.md # This file
|
||||
│ └── legacy/
|
||||
│ └── gitea-workflows/ # Archived Gitea workflows
|
||||
├── docker-compose.base.yml
|
||||
├── docker-compose.staging.yml
|
||||
├── docker-compose.prod.yml
|
||||
└── docker/
|
||||
└── php/
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
**Remote Server**:
|
||||
```
|
||||
/opt/framework-staging/ or /opt/framework-production/
|
||||
├── current/ # Active deployment
|
||||
│ ├── docker-compose.base.yml
|
||||
│ ├── docker-compose.staging.yml
|
||||
│ ├── docker/
|
||||
│ └── deploy.sh
|
||||
├── backup_20250124_153045/ # Timestamped backups
|
||||
├── backup_20250124_120000/
|
||||
├── backup_20250123_183015/
|
||||
└── failed_20250124_154512/ # Failed deployment (if rollback occurred)
|
||||
```
|
||||
|
||||
### Environment Variable Reference
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| `STAGING_HOST` | Yes* | staging.michaelschiemer.de | Staging server hostname/IP |
|
||||
| `STAGING_USER` | No | deploy | Staging SSH user |
|
||||
| `STAGING_SSH_PORT` | No | 22 | Staging SSH port |
|
||||
| `PRODUCTION_HOST` | Yes* | michaelschiemer.de | Production server hostname/IP |
|
||||
| `PRODUCTION_USER` | No | deploy | Production SSH user |
|
||||
| `PRODUCTION_SSH_PORT` | No | 22 | Production SSH port |
|
||||
| `REGISTRY` | No | localhost:5000 | Docker registry URL |
|
||||
| `IMAGE_NAME` | No | framework | Docker image name |
|
||||
| `IMAGE_TAG` | No | staging/latest | Docker image tag |
|
||||
| `SKIP_BACKUP` | No | false | Skip database backup (production) |
|
||||
| `FORCE_REBUILD` | No | false | Force Docker image rebuild |
|
||||
|
||||
*Required for respective deployment type
|
||||
|
||||
### Common Commands Reference
|
||||
|
||||
**Local Commands**:
|
||||
```bash
|
||||
# Deploy staging
|
||||
./deployment/scripts/deploy-staging.sh
|
||||
|
||||
# Deploy production
|
||||
./deployment/scripts/deploy-production.sh
|
||||
|
||||
# Rollback staging
|
||||
./deployment/scripts/rollback.sh staging
|
||||
|
||||
# Rollback production
|
||||
./deployment/scripts/rollback.sh production
|
||||
|
||||
# Test SSH connection
|
||||
ssh deploy@staging.michaelschiemer.de "echo 'SSH works'"
|
||||
```
|
||||
|
||||
**Remote Commands** (via SSH):
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Check status
|
||||
docker-compose ps
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
|
||||
# Execute command in container
|
||||
docker-compose exec production-app php console.php db:status
|
||||
|
||||
# View container logs
|
||||
docker-compose logs production-app --tail=50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-01-24
|
||||
**Framework Version**: 2.x
|
||||
**Deployment Method**: SSH-based deployment scripts
|
||||
@@ -219,3 +219,8 @@ ansible-playbook -i inventory/production.yml \
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user