CI/CD itu wajib kalau kamu mau deploy aplikasi secara profesional. GitHub Actions bikin semuanya gampang — cukup tulis workflow YAML, dan build-test-deploy jalan otomatis setiap kali push kode. Saya share cara setup dari nol.
Di sini saya bahas cara membuat CI/CD pipeline menggunakan GitHub Actions, mulai dari konsep dasar hingga deployment ke VPS production. Semua contoh dilengkapi dengan workflow YAML yang bisa langsung kamu gunakan.
Kenalan dengan CI/CD Pipeline
CI/CD terdiri dari dua konsep utama yang bekerja bersama-sama:
- Continuous Integration (CI): Setiap kali developer push kode ke repository, proses build dan test berjalan secara otomatis. Ini memastikan kode baru tidak merusak fungsionalitas yang sudah ada.
- Continuous Deployment (CD): Setelah lolos semua test, kode otomatis di-deploy ke staging atau production environment tanpa intervensi manual.
Pipeline yang baik mengurangi human error, mempercepat release cycle, dan memberikan feedback cepat kepada developer tentang kualitas kode mereka.
Kenapa Memilih GitHub Actions
GitHub Actions memiliki beberapa keunggulan dibanding tools CI/CD lain seperti Jenkins, GitLab CI, atau CircleCI:
- Terintegrasi langsung: Tidak perlu setup server terpisah, langsung berjalan di ekosistem GitHub
- Free tier generous: 2000 menit per bulan untuk private repository, unlimited untuk public
- Marketplace kaya: Ribuan pre-built actions yang bisa digunakan langsung
- YAML-based: Konfigurasi dalam bentuk file, bisa di-version control
- Multi-platform: Support Ubuntu, Windows, dan macOS runners
Struktur Dasar Workflow GitHub Actions
Setiap workflow GitHub Actions didefinisikan dalam file YAML yang disimpan di direktori .github/workflows/. Berikut struktur dasarnya:
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build project
run: npm run build
Penjelasan komponen utama:
- name: Nama workflow yang tampil di tab Actions di GitHub
- on: Trigger yang memicu workflow berjalan (push, pull_request, schedule, dll)
- jobs: Kumpulan langkah yang berjalan secara paralel atau berurutan
- runs-on: Jenis runner (virtual machine) yang digunakan
- steps: Langkah-langkah individual dalam setiap job
- uses: Menggunakan pre-built action dari marketplace
- run: Menjalankan command shell langsung
Contoh Pipeline Lengkap untuk Aplikasi Node.js
Berikut workflow lengkap yang mencakup linting, testing, building, dan deployment:
name: Node.js CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_ENV: production
APP_NAME: my-app
jobs:
lint:
name: Code Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
-- --coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.node-version }}
path: coverage/
build:
name: Build Application
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/html/${{ env.APP_NAME }}
git pull origin main
npm ci
--production
npm run build
pm2 restart ${{ env.APP_NAME }}
Deploy ke VPS dengan SSH
Untuk deploy ke VPS, kita menggunakan SSH action. Pertama, kamu perlu mengkonfigurasi secrets di repository GitHub:
- Buka repository GitHub kamu
- Klik menu Settings kemudian Secrets and variables > Actions
- Tambahkan secrets berikut:
- SERVER_HOST: IP address atau domain VPS kamu (contoh: 192.168.1.100)
- SERVER_USER: Username SSH (contoh: root atau deploy)
- SSH_PRIVATE_KEY: Isi dari private key SSH (contoh: isi file id_rsa)
Untuk generate SSH key pair jika belum punya:
ssh-keygen -t ed25519 -C "github-deploy" -f ~/.ssh/github_deploy -N ""
# Copy public key ke VPS
ssh-copy-id -i ~/.ssh/github_deploy.pub user@your-vps-ip
# Copy private key untuk disimpan di GitHub Secrets
cat ~/.ssh/github_deploy
Pipeline untuk Aplikasi PHP dengan CodeIgniter 4
Bagi pengguna PHP, berikut contoh pipeline untuk aplikasi CodeIgniter 4:
name: PHP CI/CD - CodeIgniter 4
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, json, mysql
coverage: xdebug
- name: Install Composer dependencies
run: composer install
--no-progress
--prefer-dist
- name: Copy env file
run: cp env .env
- name: Generate app key
run: php spark key:generate
- name: Run tests
run: vendor/bin/phpunit
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install dependencies
run: composer install
--no-dev
--optimize-autoloader
- name: Deploy to server
uses: SamKirkland/[email protected]
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
local-dir: ./
server-dir: /var/www/html/
exclude: |
**/.git*
**/.env*
**/tests/**
**/.github/**
writable/debugbar/**
Menggunakan Environment Variables dan Secrets
GitHub Actions menyediakan dua cara untuk menyimpan konfigurasi sensitif:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy with secrets
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
API_KEY: ${{ secrets.API_KEY }}
run: |
echo "Deploying to production..."
# Gunakan environment variables dalam script deploy
Perbedaan antara Secrets dan Variables:
- Secrets: Untuk data sensitif (password, API key, token). Nilainya tidak bisa dibaca setelah disimpan, hanya muncul di log jika kamu secara eksplisit menggunakannya.
- Variables: Untuk konfigurasi non-sensitif (URL, nama aplikasi, environment name). Bisa dilihat dan diedit oleh siapa saja yang punya akses repository.
Caching untuk Mempercepat Pipeline
Caching dependencies bisa menghemat waktu build secara signifikan:
steps:
- uses: actions/checkout@v4
# Cache untuk Node.js
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Otomatis cache folder node_modules
# Cache untuk PHP/Composer
- name: Cache Composer packages
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install
--no-progress
--prefer-dist
Scheduled Workflow dan Cron Jobs
Selain trigger dari push atau pull request, kamu juga bisa menjalankan workflow secara terjadwal:
name: Scheduled Tasks
on:
schedule:
# Setiap hari jam 2 pagi UTC
- cron: '0 2 * * *'
# Setiap hari Senin jam 8 pagi UTC
- cron: '0 8 * * 1'
jobs:
database-backup:
runs-on: ubuntu-latest
steps:
- name: Backup database via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
mysqldump -u ${{ secrets.DB_USER }} -p${{ secrets.DB_PASSWORD }} ${{ secrets.DB_NAME }} > /backups/db_$(date +%Y%m%d).sql
gzip /backups/db_$(date +%Y%m%d).sql
Matrix Strategy untuk Multi-Environment Testing
Matrix strategy memungkinkan kamu menjalankan tests di berbagai versi atau konfigurasi secara paralel:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3']
database: ['mysql', 'postgres']
exclude:
- php-version: '8.1'
database: 'postgres'
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
- name: Run tests
run: vendor/bin/phpunit
env:
DB_TYPE: ${{ matrix.database }}
Notification dan Slack Integration
kamu bisa menambahkan notifikasi Slack untuk memberitahu tim tentang status deployment:
jobs:
notify:
runs-on: ubuntu-latest
needs: [test, deploy]
if: always()
steps:
- name: Slack notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
fields: repo,message,commit,author
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Best Practices CI/CD Pipeline
Untuk mendapatkan hasil maksimal dari CI/CD pipeline kamu, ikuti best practices berikut:
- Pisahkan jobs berdasarkan fungsi: Jangan gabung lint, test, dan deploy dalam satu job. Pisahkan agar bisa berjalan paralel dan memudahkan debugging.
- Gunakan environment protection rules: Untuk production deployment, tambahkan approval step agar tidak semua push langsung ke production.
- Minimalkan secrets exposure: Jangan pernah mencetak secrets ke log. Gunakan environment variables dan mask sensitive data.
- Pin action versions: Selalu gunakan versi spesifik (actions/checkout@v4) bukan versi major (actions/checkout@main) untuk menghindari breaking changes.
- Gunakan concurrency groups: Hindari multiple deployment berjalan bersamaan yang bisa menyebabkan conflict.
concurrency:
group: production-deploy
cancel-in-progress: true
Troubleshooting Common Issues
Beberapa masalah umum yang sering terjadi saat setup CI/CD pipeline:
- Workflow tidak ter-trigger: Pastikan branch name di trigger sesuai dengan branch yang kamu push. Juga cek apakah repository sudah meng-enable Actions di Settings.
- SSH connection timeout: Pastikan VPS firewall mengizinkan koneksi dari GitHub IP ranges. Gunakan action appleboy/ssh-action yang sudah support timeout dan retry.
- Permission denied saat deploy: Pastikan user SSH memiliki permission yang cukup untuk menulis ke direktori deployment. Gunakan deploy user dengan akses terbatas, bukan root.
- Secrets tidak terbaca: Secrets tidak tersedia di pull request dari fork. Ini fitur keamanan, bukan bug.
Dengan CI/CD pipeline yang terkonfigurasi dengan baik, proses development menjadi lebih efisien, konsisten, dan andal. Mulailah dengan pipeline sederhana, lalu tambahkan fitur seiring kebutuhan tim kamu berkembang.