Taryana
Kembali ke Semua Artikel Teknis/Membangun Pipeline CI/CD Otomatis ke VPS dengan GitHub Actions, GHCR, dan Docker Compose
DevOpsCI/CDDockerGitHub ActionsGHCRNext.jsLinux

Membangun Pipeline CI/CD Otomatis ke VPS dengan GitHub Actions, GHCR, dan Docker Compose

Belajar dari pengalaman nyata menangani insiden server freeze dan OOM saat compile: bagaimana memindahkan beban build ke GitHub Actions dan GHCR membuat VPS hemat 2 vCPU tetap adem dan stabil.

1. Mengapa Menjalankan Build Langsung di Server VPS Pasti Melumpuhkan Produksi?

Pernahkah kamu berada dalam situasi serba salah di mana kamu ingin membangun aplikasi web modern dengan arsitektur tangguh seperti Next.js dan NestJS, tetapi terbentur oleh realitas anggaran infrastruktur yang hanya mengizinkan kamu menyewa VPS hemat dengan spesifikasi 2 vCPU dan 4 GB RAM?

Pengalaman menegangkan itulah yang pernah saya hadapi ketika pertama kali merilis platform web interaktif ke lingkungan produksi. Di atas kertas, spesifikasi server tersebut sebenarnya sudah lebih dari cukup untuk melayani ribuan pengunjung per jam dalam kondisi normal (runtime traffic).

Namun, mimpi buruk operasional yang sesungguhnya baru dimulai saat satu perintah dieksekusi langsung di terminal VPS: npm run build.

Begitu proses bundling dan kompilasi TypeScript dijalankan di dalam server, serangkaian malapetaka langsung melanda:

  • CPU Terkunci di 100%: Siklus prosesor terkuras habis untuk dan chunk modul.
  • Memori Melompat Menyentuh Batas RAM: Alokasi memori membengkak hingga tidak menyisakan ruang bagi kernel sistem operasi dan background service.
  • Koneksi SSH Terputus & Situs Mati: Server mendadak tidak merespons, pengunjung aktif disambut halaman error, dan sesi SSH terputus seketika.
  • Total (): Ujung-ujungnya server mengalami akibat , dan satu-satunya jalan keluar adalah melakukan paksa melalui dashboard kontrol penyedia VPS.

Dari kepanikan tersebut, saya sempat tergoda mencoba jalan pintas: me-build di laptop lokal, lalu mem-push folder .next ke GitHub. Namun cara itu justru menimbulkan malapetaka baru: ukuran repositori Git membengkak ratusan megabyte dalam beberapa hari, rawan kebocoran file secret lokal, serta ketidaksesuaian modul native C++ antara macOS lokal dan server Ubuntu Linux.

Saya sadar, kita butuh paradigma rekayasa yang benar: Jangan pernah membebani server produksi dengan tugas kompilasi kode.

Executive Summary & Core Insight

Blueprint Solusi: "Build di Luar, Jalankan di Dalam" Untuk membebaskan server VPS dari siklus build yang rakus resource, kami merancang arsitektur pipeline otomatis berbasis 5 pilar:

  1. 1GitHub Actions Cloud Runner: Memindahkan seluruh beban berat proses compile, type-check, dan bundling ke cloud runner GitHub yang bertenaga tanpa menguras 1% pun CPU VPS.
  2. 2Multi-Stage Dockerfile & Standalone Next.js: Membungkus aplikasi dengan konfigurasi output: "standalone" yang hanya menyertakan dependensi esensial, memangkas ukuran image dari 1,2 GB menjadi hanya ~118 MB.
  3. 3GitHub (): Menyimpan artefak kontainer secara privat dan aman dengan penomoran tag deterministik berbasis timestamp dan short SHA commit Git.
  4. 4SSH Rollout & Docker Compose: Server VPS cukup menarik (pull) image siap saji melalui koneksi SSH terenkripsi dan me-rollout kontainer secara mulus via docker compose.
  5. 5Automated & : Memverifikasi kesiapan aplikasi melalui endpoint /api/health sebelum mendeklarasikan deployment sukses, serta mengirim laporan otomatis ke Discord.
Diagram Arsitektur Pipeline CI/CD Otomatis: GitHub Actions → GHCR → VPSDevOps & Docker Pipeline
Memindahkan beban kompilasi Next.js ke cloud runner agar VPS hemat 2 vCPU tetap stabil dan adem
Skenario Alur:
Pinch touchpad / scroll untuk zoom • Klik-drag untuk geser (kiri, kanan, atas, bawah)
PushPush ImagePull ImageSSH Ed25519 Tunnel200 OK1. Dev WorkstationLocal RepositoryTarget Branch:origin/productionCommit Action:git push (Web Hook)Kompilasi Lokal:Zero Build Overhead(Tidak makan RAM/CPU)Webhook Triggered2. GitHub Actions RunnerCloud Isolated (ubuntu-latest)1Checkout & Setup BuildxMulti-stage cache inline2Next.js Standalone Build1.2 GB ➔ ~118 MB Minimalis3Deterministic TaggingYYYYMMDD-HHMMSS-SHABeban CPU VPS: 0% (Bebas OOM)GitHub Cloud Menanggung Semua KompilasiBuild Artifacts Sealed (~48s)3. GHCR (ghcr.io)Private Docker RegistryImage Repository:portfolio-frontendSize: ~118 MB (Compressed)Tags Strategy:• latest (active pointer)• 20260927-SHA (immutable)Automated Pruning:Simpan 3 Rilis TerakhirDigest Verified & Secured4. Production VPSUbuntu LTS (2 vCPU / 4 GB RAM)SSH Rollout Execution:docker compose pulldocker compose up -dContainer Runtime:portfolio_frontend:3000Next.js Standalone (node server.js)Otomasi Perawatan:Watchtower & Prune ImageCPU: 5-10% Sesaat (Stabil)5. Alert✓Health 200Verified💬DiscordWebhook✉SMTP AlertLive ✅

Semua Alur: Live Automated Pipeline

Alur end-to-end otomatis dari commit developer hingga rilis produksi

Tahap 0All dari 05

Setiap git push ke branch production secara otomatis memicu orkestrasi cloud GitHub Actions. Beban kompilasi diisolasi di cloud runner, image standalone dipublikasikan ke GHCR, ditarik via SSH ke VPS, diverifikasi via health check, dan dilaporkan ke Discord.

Eksekusi Perintah / Terminal SnapshotBash / Shell / Cloud Runner
$git push origin production
> Webhook event dispatched: push to refs/heads/production
> GitHub Actions workflow 'Deploy Frontend to VPS' queued.
> Pipeline status: RUNNING (Live automated orchestration).
Alur Lengkap: Build & kompilasi terisolasi 100% di cloud runner. VPS produksi bebas dari OOM dan server freeze.
Zero VPS CPU Load10x Faster (~85s)

2. Peta Topologi dan Matriks Komparasi Deployment

Sebelum kita menelaah konfigurasi teknisnya langkah demi langkah, mari kita bandingkan perbedaan kinerja operasional antara deployment manual tradisional dan modern:

Dimensi RekayasaDeployment Manual di ServerPipeline Otomatis + Dampak Produksi Nyata
Beban RAM Server VPSMelonjak hingga 3,8 GB (Rawan crash )Stabil konstan ~80 MB (Compile di Cloud)Nol risiko server freeze
Utilisasi CPU Saat Rilis100% Mengunci Server (Situs down)5% - 10% Sesaat (Container Spin-up)Situs tetap lancar bagi pengunjung
Durasi Waktu Rilis10 - 15 menit per update manual~85 detik (Push to Live otomatis)10x Lebih Cepat & Otomatis
Ukuran Paket Aplikasi1,2 GB (Folder node_modules penuh)~118 MB (Next.js Standalone Minimalis)Hemat ruang disk hingga 90%
Keamanan Source CodeSource code & .env tersimpan di serverHanya image biner di VPS, source code amanKeamanan enterprise-grade
Kemudahan RollbackSangat sulit (Harus git checkout & build ulang)Instan 2 detik (Tinggal ganti tag image)Rollback instan tanpa panik

3. Komponen Inti Arsitektur Pipeline CI/CD

A. GitHub Actions (Orchestration Engine)

Bertindak sebagai konduktor utama yang dipicu secara otomatis setiap kali ada push ke branch production, atau dijalankan secara manual melalui antarmuka workflow_dispatch dengan opsi runner ubuntu-latest atau self-hosted.

B. Multi-Stage Dockerfile Minimalis

Next.js dikompilasi menggunakan fitur output: "standalone". Hasilnya adalah folder mandiri yang memuat server Node.js minimalis dan modul yang benar-benar digunakan saja. Kontainer dijalankan di bawah akun non-root (nextjs:nodejs) demi standar keamanan tinggi.

C. GitHub Container Registry (ghcr.io)

Artefak kontainer disimpan secara privat di ghcr.io. Setiap versi rilis diberi tag unik komposit YYYYMMDD-HHMMSS-SHA serta tag pointer latest. Fitur disetel untuk mempertahankan 3 versi rilis terakhir guna menghemat kuota storage registry.

D. SSH Runner & Docker Compose Rollout

GitHub Runner tersambung ke VPS target melalui SSH terenkripsi menggunakan private key VPS_SSH_KEY, mengeksekusi login , menarik image baru, dan memperbarui layanan via docker compose up -d --remove-orphans.

E. Automated Health Check & Multi-Channel Alerting

Pipeline melakukan otomatis hingga 6 kali ke endpoint GET /api/health. Jika endpoint mengembalikan status HTTP 200, bot mengirim kartu embed hijau ke Webhook Discord. Jika aplikasi gagal merespons, pipeline dibatalkan dan alert merah dipancarkan seketika.


4. Panduan Implementasi Langkah demi Langkah (Step-by-Step)

Langkah 1: Mengaktifkan Next.js Standalone Mode

Buka file konfigurasi next.config.mjs di proyek kamu dan tambahkan opsi output: "standalone":

JAVASCRIPT Reference7 baris kode
> /** @type {import('next').NextConfig} */ | const nextConfig = { ...Klik untuk melihat implementasi lengkap →

Pengaturan ini menginstruksikan Next.js untuk secara cerdas menelusuri seluruh dependensi modul dan menyalinnya ke folder .next/standalone, sehingga kontainer produksi tidak membutuhkan folder node_modules raksasa yang berukuran gigabyte.


Langkah 2: Menyusun Dockerfile Multi-Stage Produksi

Buat file Dockerfile pada direktori root repositori dengan arsitektur 3 tahap (Stage deps, Stage builder, dan Stage runner):

DOCKERFILE Reference44 baris kode
> # Stage 1: Base dependencies | FROM node:22-alpine AS deps ...Klik untuk melihat implementasi lengkap →

Pastikan kamu juga membuat file .dockerignore agar file lokal tidak bocor ke dalam build image:

TEXT Reference10 baris kode
> Dockerfile | .dockerignore ...Klik untuk melihat implementasi lengkap →

Langkah 3: Membuat Endpoint Health Check

Buat route handler di src/app/api/health/route.ts:

TypeScript CRDT Reference13 baris kode
> import { NextResponse } from "next/server"; ...Klik untuk melihat implementasi lengkap →

Endpoint ini menjadi rujukan otomatis bagi untuk memverifikasi bahwa server Node.js telah menyala sempurna dan siap menerima trafik publik sebelum rilis dinyatakan berhasil.


Langkah 4: Setup Server VPS, Direktori & Autentikasi GHCR

1. Generate SSH Keypair untuk Deployment

Di komputer lokal, buat SSH keypair khusus deployment:

BASH Reference1 baris kode
> ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions_vps ...Klik untuk melihat implementasi lengkap →

Salin isi public key (~/.ssh/github_actions_vps.pub) ke file ~/.ssh/authorized_keys di server VPS kamu.

2. Buat Direktori Kerja Deployment

Masuk ke terminal VPS kamu dan buat direktori aplikasi:

BASH Reference3 baris kode
> sudo mkdir -p /var/www/portfolio | sudo chown -R $USER:$USER /var/www/portfolio ...Klik untuk melihat implementasi lengkap →

3. Buat File docker-compose.yml di VPS

Di dalam /var/www/portfolio, buat file docker-compose.yml:

YAML Reference27 baris kode
> services: | portfolio-frontend: ...Klik untuk melihat implementasi lengkap →

Langkah 5: Menyusun Workflow File GitHub Actions (deploy.yml)

Buat file .github/workflows/deploy.yml pada repositori kamu:

YAML Reference178 baris kode
> name: Deploy Frontend to VPS ...Klik untuk melihat implementasi lengkap →

5. Tiga Pelajaran Berharga dari Medan Produksi (War Stories)

A. Bahaya Tag latest vs Strategi Tagging Deterministik

Mengandalkan tag latest sebagai satu-satunya referensi image adalah jebakan berbahaya (anti-pattern). Jika versi rilis baru mengandung bug, kamu akan kesulitan melakukan rollback karena tag latest selalu menunjuk ke commit paling ujung. Dengan pola tag komposit YYYYMMDD-HHMMSS-SHA (seperti 20260927-142010-78ab9c4), setiap image bersifat immutable. Jika rilis baru bermasalah, rollback cukup dilakukan dalam 2 detik dengan mengubah satu variabel IMAGE_TAG di file .env server ke tag versi sebelumnya.

B. Mencegah Kebocoran Secret di Layer Docker Image

Jangan pernah menyuntikkan password database atau secret key ke dalam instruksi ENV di Dockerfile! Setiap baris ENV akan tercatat permanen di metadata layer image dan dapat dibaca siapapun via docker inspect.

  • Nilai publik yang dibutuhkan saat kompilasi frontend dipasok melalui build-args.
  • Seluruh secret sensitif diinjeksi secara murni saat runtime melalui file environment terisolasi di server VPS.

C. Pembersihan Disk Server Otomatis (Hygiene Maintenance)

Perintah docker image prune -f yang dieksekusi di akhir script SSH secara otomatis membuang image lama yang berstatus dangling tanpa menghapus image rilis aktif. Ini menjaga ruang disk server hemat kamu tetap stabil di bawah 40% kapasitas tanpa perlu pembersihan manual.


6. Hasil Riil di Produksi: Metrik Sebelum vs Sesudah

Penerapan berbasis dan Docker Compose ini memberikan perbaikan performa operasional yang sangat melegakan bagi tim:

Metrik OperasionalDeployment Manual di ServerPipeline Otomatis + Dampak Produksi Nyata
Beban RAM Server VPSLonjakan hingga 3,8 GB ( Crash)Stabil konstan ~80 MBServer 100% Bebas Crash
Utilisasi CPU Saat Rilis100% Freeze / Kernel Panic5% - 10% Sesaat (Container Spin-up)Situs tetap lancar bagi pengunjung
Waktu Siklus Rilis10 - 15 menit per update manual~85 detik (Push to Live otomatis)10x Lebih Cepat & Otomatis
Ukuran Image Kontainer1,2 GB (Node Modules Penuh)~118 MB (Next.js Standalone)Hemat ruang disk hingga 90%
Kemudahan Audit & RollbackRawan desinkronisasi lokalDeterministic SHA Tagging100% Audit Trail & Rollback 2 Detik

7. Rekomendasi Lapangan untuk Rekayasa DevOps

Keterbatasan budget infrastruktur sering kali memaksa kita menjadi engineer yang lebih disiplin dan kreatif. Dua prinsip mendasar yang selalu kami pegang:

  1. 1VPS Murah Bukan Alasan untuk Menyerah pada Tech Stack Modern: Next.js dan NestJS tetap dapat hidup berdampingan dengan sangat mulus di VPS 2 vCPU hemat biaya, asalkan arsitektur deployment-nya tepat dan tidak memaksakan proses kompilasi di tempat.
  2. 2Pemisahan Tanggung Jawab (Separation of Concerns): Mesin produksi bertugas murni melayani pengguna (serving traffic), bukan mengompilasi kode (building artifacts).

Dengan memindahkan beban build ke GitHub Actions dan mengamankan image di GitHub , VPS kamu dapat berfokus penuh pada fungsi utamanya: menyajikan aplikasi secara cepat, andal, dan tanpa gangguan bagi seluruh pengunjung.

CI/CD Pipeline Simulator
Memuat lab interaktif...

Ingin bereksplorasi lebih dalam?

Buka seluruh koleksi simulator sistem terdistribusi di Central Sandbox Playground.

Buka Central Sandbox →