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:
- Selalu backup sebelum deploy
- Implementasikan rollback mechanism
- Gunakan environment variables untuk konfigurasi
- Log semua deployment activities
- Test deployment script di staging terlebih dahulu
- 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/