CI/CD pipeline adalah tulang punggung dari praktik DevOps modern. Dengan Continuous Integration dan Continuous Deployment, Anda bisa mengotomatiskan proses build, test, dan deploy aplikasi secara konsisten dan andal. GitHub Actions, fitur bawaan dari GitHub, menawarkan solusi CI/CD yang powerful tanpa perlu tools tambahan.
Artikel ini akan membahas secara lengkap 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 Anda gunakan.
CI/CD terdiri dari dua konsep utama yang bekerja bersama-sama:
Pipeline yang baik mengurangi human error, mempercepat release cycle, dan memberikan feedback cepat kepada developer tentang kualitas kode mereka.
GitHub Actions memiliki beberapa keunggulan dibanding tools CI/CD lain seperti Jenkins, GitLab CI, atau CircleCI:
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:
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 }}
Untuk deploy ke VPS, kita menggunakan SSH action. Pertama, Anda perlu mengkonfigurasi secrets di repository GitHub:
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
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/**
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:
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
Selain trigger dari push atau pull request, Anda 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 memungkinkan Anda 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 }}
Anda 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 }}
Untuk mendapatkan hasil maksimal dari CI/CD pipeline Anda, ikuti best practices berikut:
concurrency:
group: production-deploy
cancel-in-progress: true
Beberapa masalah umum yang sering terjadi saat setup CI/CD pipeline:
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 Anda berkembang.