Salin dan Bagikan
Cara Automasi Deployment Website dengan Bash Script dan Git - Tutorial membuat deployment automation dengan bash script dan Git hooks. Implementasi CI/CD …

Cara Automasi Deployment Website dengan Bash Script dan Git

Cara Automasi Deployment Website dengan Bash Script dan Git

Automasi deployment adalah kunci untuk streamline proses development. Artikel ini membahas cara membuat deployment automation menggunakan bash script dan Git hooks untuk CI/CD pipeline yang sederhana namun powerful.

1. Setup Repository dan Git Hooks

Git Hooks Basics

Git hooks adalah script yang dieksekusi pada event tertentu dalam Git workflow.

# Lokasi hooks dalam repository
ls -la .git/hooks/

# Buat hook baru (contoh: post-receive untuk deployment)
touch .git/hooks/post-receive
chmod +x .git/hooks/post-receive

Hook Types yang Berguna

# Client-side hooks
pre-commit          # Sebelum commit dibuat
prepare-commit-msg  # Sebelum editor commit message dibuka
commit-msg          # Sebelum commit diterima
post-commit         # Setelah commit dibuat

# Server-side hooks
pre-receive         # Sebelum menerima push
update              # Sebelum update ref
post-receive        # Setelah menerima push (untuk deployment)

2. Deployment Script dengan Git

Server-side Deployment Hook

#!/bin/bash
# /var/repo/website.git/hooks/post-receive

set -euo pipefail

# Configuration
DEPLOY_DIR="/var/www/html"
GIT_DIR="/var/repo/website.git"
BACKUP_DIR="/backup/website"
BRANCH="main"
LOG_FILE="/var/log/deploy.log"

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# Main deployment logic
deploy() {
    log "Starting deployment..."
    
    # Read stdin dari git push
    while read oldrev newrev refname; do
        branch=$(git rev-parse --symbolic --abbrev-ref $refname)
        
        if [ "$branch" = "$BRANCH" ]; then
            log "Deploying branch: $branch"
            log "Commit: $newrev"
            
            # Backup current version
            if [ -d "$DEPLOY_DIR" ]; then
                backup_name="backup_$(date +%Y%m%d_%H%M%S)"
                log "Creating backup: $backup_name"
                cp -r "$DEPLOY_DIR" "$BACKUP_DIR/$backup_name"
            fi
            
            # Checkout code ke deploy directory
            log "Checking out code..."
            GIT_WORK_TREE="$DEPLOY_DIR" git checkout -f "$BRANCH"
            
            # Change ke deploy directory
            cd "$DEPLOY_DIR"
            
            # Run deployment tasks
            log "Running deployment tasks..."
            
            # Install dependencies
            if [ -f "composer.json" ]; then
                log "Installing composer dependencies..."
                composer install --no-dev --optimize-autoloader
            fi
            
            if [ -f "package.json" ]; then
                log "Installing npm dependencies..."
                npm ci --production
                log "Building assets..."
                npm run build
            fi
            
            # Set permissions
            log "Setting permissions..."
            chown -R www-data:www-data "$DEPLOY_DIR"
            find "$DEPLOY_DIR" -type d -exec chmod 755 {} \;
            find "$DEPLOY_DIR" -type f -exec chmod 644 {} \;
            
            # Clear caches
            log "Clearing caches..."
            if [ -f "artisan" ]; then
                php artisan cache:clear
                php artisan config:clear
                php artisan view:clear
                php artisan migrate --force
            fi
            
            # Restart services jika diperlukan
            if [ -f "/etc/init.d/nginx" ]; then
                log "Reloading nginx..."
                sudo systemctl reload nginx
            fi
            
            log "Deployment completed successfully!"
            
            # Send notification
            echo "Deployment successful: $newrev" | mail -s "Deployment Success" admin@example.com
        fi
    done
}

# Run deployment
deploy

Local Deployment Script

#!/bin/bash
# deploy.sh - Run locally untuk deploy ke server

set -euo pipefail

# Configuration
REMOTE_HOST="server.example.com"
REMOTE_USER="deploy"
REPO_PATH="/var/repo/website.git"
BRANCH="main"
SSH_KEY="$HOME/.ssh/deploy_key"

# Colors untuk output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Pre-deployment checks
pre_deploy_checks() {
    log_info "Running pre-deployment checks..."
    
    # Check working directory clean
    if ! git diff --quiet; then
        log_error "Working directory tidak clean. Commit atau stash perubahan terlebih dahulu."
        exit 1
    fi
    
    # Check tests pass
    if [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
        log_info "Running tests..."
        if ! ./vendor/bin/phpunit; then
            log_error "Tests failed!"
            exit 1
        fi
    fi
    
    if [ -f "package.json" ]; then
        if grep -q '"test"' package.json; then
            log_info "Running npm tests..."
            if ! npm test; then
                log_error "NPM tests failed!"
                exit 1
            fi
        fi
    fi
    
    log_info "All checks passed!"
}

# Deploy ke remote server
deploy_to_remote() {
    log_info "Deploying to $REMOTE_HOST..."
    
    # Push ke remote
    log_info "Pushing to $BRANCH branch..."
    git push origin "$BRANCH"
    
    # Trigger deployment via SSH
    log_info "Triggering deployment on remote server..."
    ssh -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" \
        "cd $REPO_PATH && git fetch origin && git reset --hard origin/$BRANCH"
    
    log_info "Deployment triggered successfully!"
}

# Rollback function
rollback() {
    log_warn "Initiating rollback..."
    
    ssh -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" \
        "cd $DEPLOY_DIR && git revert HEAD --no-edit && sudo systemctl reload nginx"
    
    log_info "Rollback completed!"
}

# Main execution
main() {
    case "${1:-deploy}" in
        deploy)
            pre_deploy_checks
            deploy_to_remote
            ;;
        rollback)
            rollback
            ;;
        *)
            echo "Usage: $0 [deploy|rollback]"
            exit 1
            ;;
    esac
}

main "$@"

3. Advanced Deployment Features

Blue-Green Deployment

#!/bin/bash
# blue-green-deploy.sh

set -euo pipefail

CURRENT_DIR="/var/www/current"
BLUE_DIR="/var/www/blue"
GREEN_DIR="/var/www/green"
NGINX_CONF="/etc/nginx/sites-available/default"
LOG_FILE="/var/log/blue-green-deploy.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# Detect current active environment
detect_active() {
    if [ -L "$CURRENT_DIR" ]; then
        current_target=$(readlink "$CURRENT_DIR")
        if [[ "$current_target" == "$BLUE_DIR" ]]; then
            echo "blue"
        else
            echo "green"
        fi
    else
        echo "blue"  # Default
    fi
}

# Deploy ke inactive environment
deploy() {
    local active=$(detect_active)
    local target
    
    if [ "$active" = "blue" ]; then
        target="$GREEN_DIR"
        log "Deploying to GREEN environment"
    else
        target="$BLUE_DIR"
        log "Deploying to BLUE environment"
    fi
    
    # Clear target directory
    rm -rf "$target"/*
    
    # Checkout new code
    GIT_WORK_TREE="$target" git checkout -f main
    
    # Setup target
    cd "$target"
    
    # Install dependencies
    if [ -f "composer.json" ]; then
        composer install --no-dev --optimize-autoloader
    fi
    
    if [ -f "package.json" ]; then
        npm ci
        npm run build
    fi
    
    # Run database migrations
    if [ -f "artisan" ]; then
        php artisan migrate --force
    fi
    
    # Health check
    log "Running health check on new environment..."
    # Tambahkan health check di sini
    
    # Switch symlink
    log "Switching to new environment..."
    rm -f "$CURRENT_DIR"
    ln -s "$target" "$CURRENT_DIR"
    
    # Reload nginx
    sudo systemctl reload nginx
    
    log "Blue-green deployment completed!"
}

main() {
    deploy
}

main "$@"

Database Migration Handler

#!/bin/bash
# migrate.sh

set -euo pipefail

DB_HOST="${DB_HOST:-localhost}"
DB_NAME="${DB_NAME:-myapp}"
DB_USER="${DB_USER:-root}"
DB_PASS="${DB_PASS:-}"
BACKUP_DIR="/backup/db"
MIGRATION_DIR="/var/www/current/database/migrations"

# Backup database before migration
backup_database() {
    local backup_name="pre_migration_$(date +%Y%m%d_%H%M%S).sql"
    local backup_path="$BACKUP_DIR/$backup_name"
    
    echo "Creating database backup: $backup_name"
    mysqldump -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$backup_path"
    gzip "$backup_path"
    
    echo "Backup created: ${backup_path}.gz"
}

# Run migrations with rollback capability
run_migration() {
    local migration_file="$1"
    
    echo "Running migration: $migration_file"
    
    if mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$migration_file"; then
        echo "Migration successful: $migration_file"
    else
        echo "Migration failed: $migration_file"
        exit 1
    fi
}

# Main migration process
main() {
    # Check prerequisites
    if [ -z "$DB_PASS" ]; then
        echo "Error: Database password not set"
        exit 1
    fi
    
    # Create backup
    backup_database
    
    # Run migrations
    for migration in "$MIGRATION_DIR"/*.sql; do
        if [ -f "$migration" ]; then
            run_migration "$migration"
        fi
    done
    
    echo "All migrations completed successfully!"
}

main "$@"

4. Environment Configuration

Environment-based Configuration

#!/bin/bash
# setup-environment.sh

set -euo pipefail

ENV="${1:-production}"
CONFIG_DIR="/etc/myapp"
ENV_FILE="$CONFIG_DIR/.env"

case "$ENV" in
    development)
        DB_HOST="localhost"
        DB_NAME="myapp_dev"
        DEBUG=true
        ;;
    staging)
        DB_HOST="staging-db.internal"
        DB_NAME="myapp_staging"
        DEBUG=false
        ;;
    production)
        DB_HOST="prod-db.internal"
        DB_NAME="myapp_prod"
        DEBUG=false
        ;;
    *)
        echo "Unknown environment: $ENV"
        exit 1
        ;;
esac

# Generate environment file
cat > "$ENV_FILE" << EOF
APP_ENV=$ENV
APP_DEBUG=$DEBUG
DB_HOST=$DB_HOST
DB_DATABASE=$DB_NAME
DB_USERNAME=app_user
DB_PASSWORD=$(openssl rand -base64 32)

CACHE_DRIVER=redis
QUEUE_DRIVER=redis

LOG_LEVEL=info
EOF

chown root:www-data "$ENV_FILE"
chmod 640 "$ENV_FILE"

echo "Environment configuration created for: $ENV"

Kesimpulan

Automasi deployment dengan bash script dan Git hooks menyederhanakan proses deployment dan mengurangi human error. Dengan Git hooks, deployment terjadi secara otomatis saat push, sementara bash script menangani task-task seperti dependency installation, database migration, dan cache clearing.

Best Practices:

  1. Selalu backup sebelum deploy
  2. Implementasikan rollback mechanism
  3. Gunakan environment variables untuk konfigurasi
  4. Log semua deployment activities
  5. Test deployment script di staging terlebih dahulu
  6. Gunakan health checks setelah deployment

Tools Tambahan:

  • Webhooks untuk external integrations
  • Slack/Discord notifications
  • Automated testing sebelum deploy
  • Canary deployment untuk zero-downtime

Artikel Terkait

Link Postingan : https://www.tirinfo.com/cara-automasi-deployment-bash-script-git/

Hendra WIjaya
Tirinfo
5 minutes.
3 February 2026