Setup CI/CD Pipeline dengan GitHub Actions: Auto Build, Test, dan Deploy ke Server
CI/CD pipeline mengubah proses deployment dari manual dan rawan error menjadi otomatis dan konsisten. GitHub Actions menyediakan platform terintegrasi di dalam repository untuk menjalankan workflow build, test, dan deploy setiap kali kode berubah.
Memahami Konsep CI/CD Pipeline
Continuous Integration (CI) memastikan setiap perubahan kode diverifikasi secara otomatis melalui build dan test. Continuous Deployment (CD) melanjutkan proses dengan mendeploy aplikasi yang lolos test ke server secara otomatis. Kombinasi keduanya menjamin bahwa bug terdeteksi sejak awal dan deployment berjalan tanpa intervensi manual.
Workflow di GitHub Actions tersusun atas beberapa komponen: event trigger yang menentukan kapan workflow berjalan, jobs yang berisi langkah-langkah eksekusi, dan runners yang menyediakan environment eksekusi. Setiap job berjalan di environment terisolasi sehingga proses build dan test tidak saling mengganggu.
Struktur Dasar Workflow File
Workflow didefinisikan dalam format YAML di direktori .github/workflows/. File berikut menunjukkan konfigurasi dasar untuk build dan test aplikasi Node.js.
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Jalankan lint
run: npm run lint
- name: Jalankan test
run: npm test
- name: Build aplikasi
run: npm run buildStruktur di atas mengikuti alur standar: checkout kode, setup environment, install dependencies, lint, test, dan build. Setiap step berjalan secara berurutan — jika satu step gagal, seluruh job akan berhenti dan GitHub akan menampilkan notifikasi error.
Menambahkan Deployment Step
Setelah build dan test berhasil, langkah berikutnya adalah mendeploy ke server. Kita akan menggunakan SSH untuk menghubungkan runner ke server target dan menjalankan perintah deployment.
name: CI/CD Pipeline
on:
push:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Jalankan lint
run: npm run lint
- name: Jalankan test
run: npm test
- name: Build aplikasi
run: npm run build
deploy:
needs: build-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy ke server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/app
git pull origin main
npm ci --production
npm run build
pm2 restart appJob deploy memiliki dependensi pada build-and-test melalui needs. Artinya deployment hanya berjalan jika semua test berhasil. Kondisi if: github.ref == 'refs/heads/main' memastikan deployment hanya dilakukan dari branch main, bukan dari pull request.
Secrets seperti SERVER_HOST, SERVER_USER, dan SSH_PRIVATE_KEY disimpan secara terenkripsi di bagian Settings > Secrets pada repository GitHub. Pendekatan ini menjaga kredensial tetap aman dan tidak terekspos di dalam file workflow.
Penting untuk dicatat: workflow di atas menggunakan npm ci alih-alih npm install. Perintah npm ci membaca langsung dari package-lock.json dan menghapus node_modules yang ada sebelum install ulang. Hasilnya lebih deterministic dan cepat dibandingkan npm install yang bisa menimbulkan perbedaan versi antara environment development dan produksi.
Mengelola Environment Variables
Environment variables memungkinkan konfigurasi yang berbeda antara staging dan production tanpa mengubah kode. GitHub Actions mendukung definisi environment variables di level workflow, job, maupun step.
jobs:
build-and-test:
runs-on: ubuntu-latest
env:
NODE_ENV: test
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Jalankan test dengan env
run: npm test
env:
API_TIMEOUT: 5000Variabel yang didefinisikan di level job berlaku untuk semua step dalam job tersebut. Step-level variables mengoverride job-level variables jika ada nama yang sama. Gunakan secrets untuk data sensitif seperti API key dan database URL — nilai secrets tidak pernah tampil di log.
Optimasi Workflow dengan Caching
Build berulang dapat memakan waktu jika dependencies diunduh ulang setiap kali. Caching mengatasi masalah ini dengan menyimpan data yang jarang berubah — seperti node_modules — agar tersedia langsung di eksekusi berikutnya.
steps:
- name: Checkout kode
uses: actions/checkout@v4
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- name: Install dependencies
run: npm ciKey cache menggunakan hash dari package-lock.json. Jika file ini berubah (misalnya ada dependency baru), cache akan terbentuk ulang. Jika tidak berubah, runner akan mengambil cache yang sudah ada sehingga proses install lebih cepat. Parameter restore-keys menyediakan fallback jika hash tidak cocok — runner akan mencoba mencari cache terdekat yang tersedia.
Selain caching dependencies, artifact caching juga membantu untuk file build. Jika build menghasilkan file besar seperti Docker image atau compiled assets, kita dapat menggunakan actions/upload-artifact dan actions/download-artifact untuk membagi file antar job tanpa mengulang proses build. Pendekatan ini mempercepat pipeline secara signifikan pada repository dengan build time yang panjang.
Monitoring dan Notifikasi
Workflow yang baik memberikan feedback ketika terjadi kegagalan. GitHub Actions mendukung notifikasi melalui email secara default, tetapi integrasi Slack atau Discord memberikan visibilitas yang lebih baik untuk tim.
notify-on-failure:
needs: [build-and-test, deploy]
runs-on: ubuntu-latest
if: failure()
steps:
- name: Kirim notifikasi Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Deployment gagal di ${{ github.repository }}\nCommit: ${{ github.sha }}\nLink: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}Job notify-on-failure berjalan hanya ketika job yang terdaftar di needs gagal, berkat kondisi if: failure(). Notifikasi berisi informasi repository, commit hash, dan link langsung ke log workflow sehingga developer dapat segera menginvestigasi masalah.
Untuk pipeline yang lebih kompleks, pertimbangkan menambahkan step rollback otomatis. Jika deployment gagal setelah build berhasil, rollback dapat mengembalikan server ke versi terakhir yang stabil. Pendekatan sederhana: simpan versi terakhir yang berhasil di tag Git, lalu gunakan script git checkout ke versi tersebut saat failure() terdeteksi. Alternatifnya, gunakan fitur concurrency di GitHub Actions untuk membatalkan deployment yang sedang berjalan ketika commit baru masuk.
Mau memperdalam skill DevOps secara sistematis? Bergabunglah dengan Web Development Bootcamp di Rumah Coding. Kurikulum praktis dengan proyek real-world dan mentorship dari praktisi industri.