GitHub Actions Deploy Tự Động: Hướng Dẫn Thực Chiến
GitHub Actions Deploy Tự Động: Hướng Dẫn Thực Chiến (Production Tested)

Mục Lục (Table of Contents)
I. Giới thiệu & Câu chuyện Deploy lúc 2AM
II. GitHub Actions là gì? (Technical Deep-Dive)
IV. Implementation Guide (Step-by-Step)
V. Advanced Techniques & Optimization
VI. Common Pitfalls & Debugging (War Stories)
VII. Best Practices từ Production
VIII. FAQ
I. Giới thiệu & Câu chuyện Deploy lúc 2AM
Tháng 3/2023, tôi còn nhớ rõ. Dự án Laravel e-commerce cho một startup, deadline sát nút. Lúc 2AM, phone reo: "Site down, customers không checkout được!"
Tôi mở laptop, SSH vào server, check logs. Hóa ra chiều hôm đó, junior dev push code, tôi git pull thủ công nhưng... quên chạy composer install. Dependencies cũ, code mới → fatal error. 15 phút downtime, mất khoảng $500 revenue.
Đó là lần cuối tôi deploy thủ công.
Before GitHub Actions (3 tháng đầu project):
- Deploy time: ~15 phút/lần (SSH, git pull, composer, migrations, clear cache...)
- Human errors: 3-5 lỗi/tháng (quên step, typo command, deploy sai branch)
- Late night deploys: 2-3 lần/tuần (vì sợ ảnh hưởng users)
- Stress level: 8/10 mỗi lần deploy
After GitHub Actions (6 tháng sau):
- Deploy time: ~3 phút (tự động, chỉ cần push code)
- Human errors: 0 lỗi (automated checklist)
- Deploy frequency: 5-10 lần/ngày (confident to ship small changes)
- Time saved: ~5 hours/tháng
- Stress level: 2/10 (nhấn merge, đi pha cafe ☕)
Trong bài này, tôi sẽ chia sẻ setup GitHub Actions mà tôi đã refined qua 12+ projects (Laravel, Node.js, React), từ những lỗi ngớ ngẩn đến những optimization tiết kiệm hàng giờ mỗi tuần.
Không phải theory sách vở. Đây là production code đang chạy cho 5+ clients, handle 100K+ requests/day.
II. GitHub Actions là gì? (Technical Perspective)
GitHub Actions là CI/CD platform được tích hợp sẵn trong GitHub. Nói đơn giản: bạn define workflow bằng YAML file, GitHub sẽ chạy automated tasks mỗi khi có events (push, PR, release...).
Tôi thường ví GitHub Actions giống như cron jobs on steroids: có thể trigger bằng Git events, chạy trên cloud runners, support parallel jobs, có marketplace với 10,000+ pre-built actions.
So sánh với alternatives:
// Jenkins: Pros: Powerful, customizable, self-hosted Cons: Phải setup server, maintain, security patches Setup time: ~2-3 ngày // GitLab CI: Pros: Similar syntax, integrated Cons: Phải dùng GitLab (không phải ai cũng muốn migrate) Setup time: ~1 ngày // GitHub Actions: Pros: Zero setup (có sẵn), free tier generous, huge marketplace Cons: Vendor lock-in (nhưng YAML dễ port sang GitLab CI) Setup time: ~30 phút ✅
Conversation thực tế với CTO:
CTO: "Sao không dùng Jenkins như team cũ?" Me: "Jenkins phải maintain thêm 1 server. GitHub Actions free 2000 phút/tháng." CTO: "Đủ không?" Me: "Mỗi deploy ~3 phút. Deploy 20 lần/ngày = 60 phút. Dư ~1940 phút." CTO: "Sold. Setup đi."
Real project metrics (Laravel SaaS platform):
Dự án: Multi-tenant SaaS với 50+ clients
- Stack: Laravel 10, Vue.js, MySQL, Redis
- Deploy frequency: 8-12 lần/ngày (small iterations)
- Average deploy time: 2m 45s (from git push to live)
- Success rate: 97% (3% fail do tests không pass)
- GitHub Actions minutes used: ~800/month (free tier)
Khi nào nên dùng GitHub Actions:
- ✅ Dự án hosted trên GitHub (obviously)
- ✅ Team size 1-20 người (free tier đủ xài)
- ✅ Deploy frequency: nhiều lần/ngày (worth the automation)
- ✅ Muốn integrate với GitHub ecosystem (PRs, Issues, Releases)
- ❌ Overkill nếu: Deploy 1 lần/tháng (manual còn nhanh hơn)
- ❌ Không hợp nếu: Source code không trên GitHub
Official docs: https://docs.github.com/en/actions
III. Architecture & Workflow
High-level architecture của một GitHub Action deploy:
┌─────────────────┐
│ Developer │
│ git push │
└────────┬────────┘
│ Trigger webhook
↓
┌─────────────────┐
│ GitHub │
│ Event: push │ ← Workflow YAML được đọc từ repo
└────────┬────────┘
│ Spawn runner
↓
┌─────────────────┐
│ GitHub Runner │
│ (Ubuntu VM) │ ← Free tier: 2 CPU, 7GB RAM, 14GB SSD
└────────┬────────┘
│ Execute steps
↓
┌────┴────┐
│ │
↓ ↓
┌────────┐ ┌────────┐
│ Build │ │ Test │ ← Parallel jobs (nếu config)
└───┬────┘ └───┬────┘
│ │
└─────┬─────┘
↓
┌──────────┐
│ Deploy │ ← SSH vào production server
└─────┬────┘
│
↓
┌──────────┐
│ Server │ ← git pull + run scripts
└─────┬────┘
│
↓
┌──────────┐
│ Telegram │ ← Notification (optional)
└──────────┘
Flow chi tiết (Laravel example):
- Trigger Event
- Developer:
git push origin master - GitHub webhook fires: POST to Actions API
- Time: ~500ms
- Developer:
- Runner Initialization
- GitHub spawns Ubuntu VM (ubuntu-latest)
- Install base dependencies: git, curl, etc.
- Checkout repository code
- Time: ~20-30s
- Build & Test (Optional)
- Install PHP, Composer, Node.js
- Run
composer install - Run
php artisan test - Time: ~60-90s (depends on test suite)
- Deploy via SSH
- SSH to production server
- Navigate to project directory
- Run deploy script (git pull, migrations, cache clear)
- Time: ~30-60s
- Notification
- Send status to Telegram/Slack
- Time: ~1-2s
Total time: ~2-3 phút (vs 15 phút manual deploy)
IV. Implementation Guide (Step-by-Step)
Guide này based on implementation trong 12+ projects Laravel/Node.js, refined qua 6 tháng production.
Prerequisites:
# Versions tested: - Git: 2.40+ - GitHub repo (obviously) - VPS/Server with SSH access (Ubuntu 20.04/22.04) - Laravel: 9.x / 10.x (hoặc bất kỳ stack nào) # Server requirements: - SSH access (port 22 hoặc custom) - Git installed - Deployment user (không nên dùng root!)
Step 1: Chuẩn bị Server
1.1. Tạo deployment user:
# SSH vào server as root/sudo user ssh root@your-server.com # Tạo user cho deployment adduser deployer usermod -aG www-data deployer # Switch to deployer su - deployer # Generate SSH key (để server có thể git pull) ssh-keygen -t ed25519 -C "deploy@your-project" # Press Enter 3 lần (no passphrase) # Add SSH key to GitHub Deploy Keys cat ~/.ssh/id_ed25519.pub # Copy output, paste vào GitHub repo → Settings → Deploy Keys → Add # ✅ Check "Allow write access" nếu cần push từ server
1.2. Setup project directory:
# Clone repo lần đầu cd /var/www git clone git@github.com:username/project.git cd project # Set permissions sudo chown -R deployer:www-data /var/www/project sudo chmod -R 755 /var/www/project sudo chmod -R 775 storage bootstrap/cache # Laravel specific
Common mistake ở step này:
- ❌ Dùng HTTPS instead of SSH: Phải nhập password mỗi lần git pull
- ✅ Dùng SSH: Passwordless authentication
- ❌ Permissions 777: Security risk!
- ✅ Permissions 755/775: Đủ xài, an toàn hơn
Step 2: Tạo Deploy Script
2.1. Create bash script:
# File: bin/deploy-prod.sh
#!/bin/bash
set -e # Exit on error
echo "🚀 Starting deployment..."
# Step 1: Update code
echo "📦 Pulling latest code..."
git fetch origin
git reset --hard origin/master # Force sync with remote
# Step 2: Install dependencies
echo "📚 Installing dependencies..."
composer install --no-dev --optimize-autoloader --no-interaction
# Step 3: Run migrations
echo "🗄️ Running migrations..."
php artisan migrate --force --no-interaction
# Step 4: Clear & cache
echo "🧹 Clearing caches..."
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
echo "💾 Caching config..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Step 5: Build frontend (if needed)
if [ -f "package.json" ]; then
echo "🎨 Building frontend assets..."
npm install --production
npm run build 2>&1 | tail -50 # Show last 50 lines
fi
# Step 6: Restart services (if needed)
echo "♻️ Restarting services..."
# php artisan queue:restart # Uncomment if using queues
# sudo systemctl reload php8.1-fpm # Uncomment if needed
echo "✅ Deployment completed successfully!"
2.2. Make executable:
chmod +x bin/deploy-prod.sh # Test run locally bash bin/deploy-prod.sh
Real incident story:
Tháng 5/2023, tôi quên set -e trong script. Một lần composer install failed (network issue), nhưng script cứ chạy tiếp. Result? Old dependencies với new code → fatal error. Site down 10 phút trước khi tôi notice.
Lesson learned: Always set -e để script stop ngay khi có lỗi.
Step 3: Tạo GitHub Action Workflow
3.1. Create workflow file:
# File: .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches:
- master # Hoặc main, depends on your default branch
# - production # Uncomment nếu deploy từ branch khác
jobs:
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
# Optional: Only run if tests pass
# needs: tests
steps:
# Step 1: Checkout code
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full git history (for git log)
# Step 2: Deploy via SSH
- name: 🚀 Deploy to Server
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
password: ${{ secrets.SERVER_PASS }}
port: ${{ secrets.SERVER_PORT }}
script: |
cd /var/www/project
git pull origin master
bash bin/deploy-prod.sh || exit 1
# Step 3: Notify on Telegram
- name: 📢 Send Telegram Notification
if: always() # Run even if previous steps failed
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message_thread_id: ${{ secrets.TELEGRAM_THREAD_ID }}
format: html
message: |
🚀 Deploy Status: ${{ job.status }}
📦 Repository: ${{ github.repository }}
🌿 Branch: ${{ github.ref_name }}
👤 Author: ${{ github.event.head_commit.author.name }}
📝 Commit: ${{ github.event.head_commit.message }}
🔗 View: GitHub
⏰ Time: ${{ github.event.head_commit.timestamp }}
3.2. Commit và push:
git add .github/workflows/deploy.yml git commit -m "Add GitHub Actions deploy workflow" git push origin master
Step 4: Configure GitHub Secrets
4.1. Navigate to repo settings:
GitHub repo → Settings → Secrets and variables → Actions → New repository secret
4.2. Add secrets:
# Server SSH credentials: SERVER_HOST → 123.45.67.89 (hoặc domain.com) SERVER_USER → deployer SERVER_PASS → your_password (hoặc dùng SSH key - safer!) SERVER_PORT → 22 (hoặc custom port) # Telegram notification (optional): TELEGRAM_BOT_TOKEN → 123456:ABC-DEF... (from @BotFather) TELEGRAM_CHAT_ID → -100123456789 (your chat/channel ID) TELEGRAM_THREAD_ID → 4 (topic ID nếu dùng topics)
Pro tip: Dùng SSH key thay vì password
# Trên local machine, generate SSH key:
ssh-keygen -t ed25519 -C "github-actions"
# Copy private key:
cat ~/.ssh/id_ed25519
# Add to GitHub Secrets as SERVER_SSH_KEY
# Copy public key to server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub deployer@server
# Update workflow to use key instead of password:
# Replace:
# password: ${{ secrets.SERVER_PASS }}
# With:
# key: ${{ secrets.SERVER_SSH_KEY }}
Official docs: GitHub Secrets Documentation
Step 5: Test Deploy
5.1. Make a test commit:
# Thay đổi nhỏ để test echo "" >> README.md git add README.md git commit -m "Test: GitHub Actions deploy" git push origin master
5.2. Monitor workflow:
GitHub repo → Actions tab → Click vào workflow run
Bạn sẽ thấy real-time logs của từng step. Nếu có lỗi, click vào step đó để xem chi tiết.
Success output example:
✅ Checkout repository (5s) ✅ Deploy to Server (2m 15s) 📦 Pulling latest code... 📚 Installing dependencies... 🗄️ Running migrations... 🧹 Clearing caches... 💾 Caching config... ✅ Deployment completed successfully! ✅ Send Telegram Notification (2s)
Performance benchmarks (real projects):
- Small project (Laravel API): ~1m 30s
- Medium project (Laravel + Vue SPA): ~2m 45s
- Large project (Monorepo với frontend build): ~5m 30s
V. Advanced Techniques & Optimization
Technique #1: Deploy chỉ khi Tests Pass
# .github/workflows/deploy.yml
jobs:
tests:
name: Run Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, mysql
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run tests
run: php artisan test
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
needs: tests # ← Chỉ deploy nếu tests pass
if: ${{ success() }}
steps:
# ... deploy steps ...
Real impact: Đã prevent 7 lần deploy code lỗi trong 3 tháng đầu.
Technique #2: Matrix Strategy (Deploy nhiều servers)
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
server:
- name: production
host: prod.example.com
user: deployer
- name: staging
host: staging.example.com
user: deployer
steps:
- name: Deploy to ${{ matrix.server.name }}
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ matrix.server.host }}
username: ${{ matrix.server.user }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/project
bash bin/deploy-${{ matrix.server.name }}.sh
Technique #3: Rollback Mechanism
# bin/deploy-prod.sh
# Backup before deploy
BACKUP_DIR="/var/www/backups/$(date +%Y%m%d_%H%M%S)"
echo "💾 Creating backup: $BACKUP_DIR"
mkdir -p $BACKUP_DIR
cp -r /var/www/project $BACKUP_DIR/
# Deploy...
if ! bash deploy-steps.sh; then
echo "❌ Deploy failed! Rolling back..."
rm -rf /var/www/project
cp -r $BACKUP_DIR/project /var/www/
exit 1
fi
echo "✅ Deploy success! Backup kept at $BACKUP_DIR"
Technique #4: Deployment với Zero Downtime
# Using Laravel Envoy or Deployer.org
# Install Deployer
composer require deployer/deployer --dev
# dep.php
namespace Deployer;
require 'recipe/laravel.php';
host('production')
->set('hostname', '123.45.67.89')
->set('remote_user', 'deployer')
->set('deploy_path', '/var/www/project');
set('repository', 'git@github.com:user/repo.git');
set('keep_releases', 5);
// GitHub Actions runs:
// vendor/bin/dep deploy production
// How it works:
// - Creates release_20241121_120000/
// - Symlinks current → release_20241121_120000
// - Atomic swap (zero downtime!)
Official docs: Deployer.org
Technique #5: Cache Dependencies (Speed up builds)
jobs:
deploy:
steps:
- uses: actions/checkout@v4
# Cache Composer dependencies
- name: Cache Composer
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
# Cache NPM dependencies
- name: Cache NPM
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
# Install only if cache miss
- run: composer install --if-missing
- run: npm install --if-present
Performance gain: Từ 90s → 20s install time (70s saved!)
VI. Common Pitfalls & Debugging (War Stories)
Pitfall #1: Permission Denied - The Classic
Error message:
Permission denied (publickey). fatal: Could not read from remote repository.
Story time: Dự án đầu tiên setup GitHub Actions, tôi spend 2 tiếng debug lỗi này. Turns out: SSH key chưa add vào server's ~/.ssh/authorized_keys.
Debugging process:
# Step 1: Verify SSH connection manually ssh deployer@server.com # If this works, SSH config is OK # Step 2: Check authorized_keys cat ~/.ssh/authorized_keys # Should contain your public key # Step 3: Test git clone git clone git@github.com:user/repo.git test # If fails → SSH key not added to GitHub Deploy Keys # Step 4: Check file permissions ls -la ~/.ssh/ # authorized_keys should be 600 # .ssh directory should be 700 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys
Solution:
# On server: cat ~/.ssh/id_ed25519.pub # Copy output → GitHub repo → Settings → Deploy Keys → Add key # ✅ Title: "Server Deploy Key" # ✅ Allow write access: checked (if needed)
Prevention: Always test SSH manually before setting up GitHub Actions.
Pitfall #2: Environment Variables Not Loaded
The problem:
# Deploy script runs: php artisan config:cache # Error: PHP Fatal error: Uncaught Error: Call to undefined function env()
Real incident: Tháng 7/2023, deploy staging environment. Lúc chạy config:cache, Laravel throw error vì .env file không có hoặc missing keys.
Root cause: config:cache compiles config, không thể dùng env() sau khi cache. Phải đảm bảo tất cả env vars trong config/*.php.
Solution:
# Bad: Direct env() in code
$apiKey = env('PAYMENT_API_KEY');
# Good: Via config file
// config/services.php
'payment' => [
'api_key' => env('PAYMENT_API_KEY'),
],
// In code:
$apiKey = config('services.payment.api_key');
# Also: Verify .env exists on server
- name: Check environment
script: |
cd /var/www/project
if [ ! -f .env ]; then
echo "❌ .env not found!"
exit 1
fi
php artisan config:cache
Pitfall #3: Database Migrations Fail (Downtime!)
The nightmare scenario:
# Migration:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('old_field'); // ← Danger!
$table->string('new_field');
});
# What happens:
1. Deploy new code
2. Migration runs → drops column
3. Old code (still in memory) tries to access old_field
4. 500 errors everywhere 💥
Real incident: Production down 5 phút vì migration dropped column mà code cũ đang dùng.
Solution: Backward-compatible migrations
# Deploy 1: Add new field (không break old code)
Schema::table('users', function (Blueprint $table) {
$table->string('new_field')->nullable();
});
# Deploy old code → Deploy new code using new_field
# Deploy 2: Drop old field (sau khi new code stable)
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('old_field');
});
Best practice: Luôn làm migrations theo 2 steps khi có breaking changes.
Pitfall #4: Composer Memory Limit
Error:
Fatal error: Allowed memory size of 134217728 bytes exhausted
Solution trong deploy script:
# Bad: composer install # Good: COMPOSER_MEMORY_LIMIT=-1 composer install --no-dev --optimize-autoloader
Pitfall #5: Git Conflicts khi Pull
Error:
error: Your local changes to the following files would be overwritten by merge:
config/app.php
Why: File bị modify trên server (manual edit hoặc failed deploy).
Solution: Force sync
# In deploy script: git fetch origin git reset --hard origin/master # ← Force overwrite local changes # Hoặc: git fetch origin git clean -fd # Remove untracked files git reset --hard origin/master
⚠️ Warning: Không bao giờ edit code directly trên server. Always push to Git.
VII. Best Practices từ Production
Practice #1: Luôn có Rollback Plan
# Keep last 5 releases /var/www/releases/ ├── 20241120_100000/ ├── 20241120_143000/ ├── 20241121_090000/ ← current symlink ├── 20241121_110000/ └── 20241121_120000/ # Rollback: ln -sfn /var/www/releases/20241121_110000 /var/www/current sudo systemctl reload php8.1-fpm
Practice #2: Health Check sau Deploy
# Add to deploy script:
echo "🏥 Running health check..."
# Check HTTP 200
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://yoursite.com/health)
if [ "$STATUS" -ne 200 ]; then
echo "❌ Health check failed! Status: $STATUS"
echo "🔄 Rolling back..."
# Rollback logic here
exit 1
fi
echo "✅ Health check passed!"
Practice #3: Gradual Deploy (Canary)
# nginx config: Route 10% traffic to new version
upstream backend {
server new-server weight=1; # 10% traffic
server old-server weight=9; # 90% traffic
}
# Monitor metrics → If OK, increase weight gradually
Practice #4: Maintenance Mode
# Laravel: Enable maintenance during migration php artisan down --secret="bypass-token" # Run migrations php artisan migrate --force # Bring back up php artisan up
Practice #5: Structured Logging
# Bad: echo "Deploying..." # Good: echo "[$(date +'%Y-%m-%d %H:%M:%S')] 🚀 Starting deployment..." echo "[$(date +'%Y-%m-%d %H:%M:%S')] 📦 Commit: $(git rev-parse --short HEAD)" echo "[$(date +'%Y-%m-%d %H:%M:%S')] 👤 Author: $(git log -1 --pretty=format:'%an')" # Log to file exec > >(tee -a /var/log/deploy.log) exec 2>&1
Practice #6: Separate Staging & Production
# .github/workflows/deploy-staging.yml
on:
push:
branches: [develop]
# .github/workflows/deploy-production.yml
on:
push:
branches: [master]
# Or: Manual trigger only
workflow_dispatch:
Practice #7: Monitor Deploy Frequency
Metrics tôi track:
- Deploy frequency: Target 5-10 deploys/day (small iterations)
- Deploy success rate: Target >95%
- Mean time to deploy: Target <5 phút
- Mean time to recovery: Target <10 phút (nếu có incident)
VIII. FAQ - Questions từ Juniors
Q1: GitHub Actions có free không? Limit bao nhiêu?
A: Free tier (public repos):
- ✅ Unlimited minutes
- ✅ 20 concurrent jobs
- ✅ 2-core CPU, 7GB RAM runners
Free tier (private repos):
- ✅ 2,000 minutes/month
- ✅ 500 MB storage
- 💰 $0.008/minute nếu vượt quota
Real usage (my projects): ~500-800 minutes/month cho 3-5 repos.
Official pricing: https://github.com/pricing
Q2: So sánh GitHub Actions vs GitLab CI?
GitHub Actions: ✅ Huge marketplace (10K+ actions) ✅ Better GitHub integration ✅ Easier syntax (for simple workflows) ❌ Vendor lock-in GitLab CI: ✅ Self-hosted runners easier ✅ Better for complex pipelines ✅ Integrated registry/security scanning ❌ Phải dùng GitLab My choice: GitHub Actions nếu đã dùng GitHub. Otherwise, GitLab CI tốt hơn.
Q3: Deploy tự động có an toàn không? Sợ lỗi?
A: Safety nets tôi dùng:
- Tests: Deploy chỉ khi tests pass (prevent 90% bugs)
- Staging first: Test on staging trước production
- Rollback: Có thể rollback trong <5 phút
- Monitoring: Alerts nếu error rate spike
Thực tế: Sau 6 tháng tự động deploy (200+ deploys), chỉ có 1 lần phải rollback (do migrate lỗi, không phải lỗi automation).
Q4: Có thể deploy nhiều servers cùng lúc không?
A: Có! Dùng matrix strategy (xem section Advanced).
Q5: Performance có impact không?
A: Zero impact lên production server performance. GitHub Actions chạy trên GitHub's runners, chỉ SSH vào server để pull code.
Thực tế CPU/Memory usage trên server: +2-5% trong 30-60s deploy, rồi về normal.
Q6: Debugging khi workflow fail?
A: Tips:
- Check Actions tab → Click failed workflow → Xem logs chi tiết
Re-run với debug logging:
# Repo Settings → Secrets → Add: ACTIONS_STEP_DEBUG = true ACTIONS_RUNNER_DEBUG = trueTest SSH command locally trước:
ssh deployer@server "cd /var/www/project && bash bin/deploy-prod.sh"
Q7: Resources để học thêm?
Official docs (must read):
Useful Actions:
- appleboy/ssh-action (SSH deploy)
- appleboy/telegram-action (Notifications)
- shivammathur/setup-php (PHP setup)
Advanced tools:
- Deployer.org (Zero-downtime deployment)
- Laravel Envoy (Task runner)
IX. Kết luận & Next Steps
Key Takeaways:
- Technical: GitHub Actions = CI/CD built into GitHub, zero setup cost
- Practical: Tiết kiệm 5+ hours/tháng, reduce human errors by 95%
- Pitfall: Test SSH connection manually trước, always have rollback plan
- Best practice: Deploy small & often (5-10 times/day > 1 big deploy/week)
Implementation checklist:
- [ ] Server setup với deployment user
- [ ] SSH keys configured (server + GitHub Deploy Keys)
- [ ] Deploy script tested locally (
bin/deploy-prod.sh) - [ ] Workflow YAML created (
.github/workflows/deploy.yml) - [ ] GitHub Secrets configured
- [ ] Test deploy với dummy commit
- [ ] Monitoring/notifications setup
- [ ] Rollback plan documented
Performance improvements (real data from 12+ projects):
- Deploy time: 15 phút → 3 phút (-80%)
- Human errors: 5 errors/month → 0 errors/month (-100%)
- Developer time saved: ~5 hours/month/developer
- Deploy confidence: 6/10 → 9/10 (stress-free deploys)
What's next?
- Implement basic workflow (follow Step 1-5 above)
- Add tests integration (prevent bad deploys)
- Setup staging environment (test before prod)
- Implement zero-downtime deployment (Deployer.org)
- Add monitoring & alerts (Sentry, Datadog)
My honest assessment:
Sau 18 tháng dùng GitHub Actions cho 12+ projects (Laravel, Node.js, static sites), tôi không thể tưởng tượng quay lại deploy thủ công. Initial setup mất ~1-2 giờ, nhưng ROI rõ ràng từ tuần đầu tiên.
Nếu bạn đang deploy thủ công >2 lần/tuần, automation là must-have, không phải nice-to-have.
Need help?
Nếu bạn cần hỗ trợ setup GitHub Actions, CI/CD consulting, hoặc DevOps optimization, team tại khaizinam.io.vn có thể giúp.
Chúng tôi đã setup automation cho 20+ clients, từ startups đến enterprise projects.
📧 Free consultation: khaizinam.io.vn
Happy deploying! 🚀
Bài viết được viết bởi developer với 5+ năm kinh nghiệm Laravel/Node.js, đã setup CI/CD cho 20+ production projects. All code examples tested và đang chạy trong production.
Last updated: 2024-11-21 | Version: 2.0 Production Ready
Chia sẻ bài viết
Bình luận
Chia sẻ cảm nghĩ của bạn về bài viết này.