helipack.json: Panduan Lengkap Konfigurasi Build & Deploy di Helipod
Bài viết này được viết bằng tiếng Indonesia.
Helipod dirancang agar zero config: cukup push kode dan langsung live. Tapi untuk kebutuhan yang lebih spesifik, kamu bisa memberi instruksi tambahan ke Helipack lewat satu file: helipack.json.
File ini ditempatkan di root repository kamu, dan Helipack akan membacanya saat build untuk meng-override perilaku default.
Struktur helipack.json#
Ini adalah semua opsi yang tersedia:
{
"build": {
"dockerfile": "string",
"sourcefile": "string"
},
"run": {
"before": "string",
"command": "string",
"after": "string",
"port": 8000,
"isTcp": false
},
"health": {
"path": "/health",
"duration": 15
},
"volume": {
"mountPath": "/app/storage",
"size": 5
},
"env": {
"KEY": "value"
},
"spec": {
"cpu": 1,
"memory": 512
},
"packages": {
"apk": [],
"apt": [],
"pecl": [],
"phpext": [],
"pip": []
}
}
Mari kita bahas setiap bagian satu per satu.
build: Konfigurasi Build#
build.dockerfile#
Gunakan Dockerfile kustom alih-alih Dockerfile yang di-generate Helipack.
{
"build": {
"dockerfile": "docker/Dockerfile.production"
}
}
Path relatif dari root repository. Berguna jika kamu punya Dockerfile sendiri di subfolder, atau memiliki beberapa Dockerfile untuk environment berbeda.
build.sourcefile#
Khusus untuk Function Pod (serverless function). Menentukan nama file yang menjadi entry point.
{
"build": {
"sourcefile": "handler.ts"
}
}
run: Konfigurasi Runtime#
run.port#
Override port default yang diexpose aplikasi. Helipack mendeteksi port dari EXPOSE di Dockerfile, tapi kamu bisa override di sini.
{
"run": {
"port": 8080
}
}
Kapan dipakai: Jika aplikasi kamu jalan di port non-standard, atau jika Helipack mendeteksi port yang salah.
run.command#
Override start command default. Helipack punya default command per framework (gunicorn untuk Flask/Django, node dist/main untuk NestJS, dll), tapi kamu bisa override.
{
"run": {
"command": "gunicorn myapp.wsgi:application --bind 0.0.0.0:8000 --workers 4 --timeout 120"
}
}
Contoh lain:
{
"run": {
"command": "uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 2 --loop uvloop"
}
}
{
"run": {
"command": "node --max-old-space-size=2048 dist/main.js"
}
}
run.before#
Command yang dijalankan sebelum start command, setiap kali ada deployment baru. Ideal untuk database migration.
{
"run": {
"before": "php artisan migrate --force"
}
}
Contoh untuk berbagai framework:
{ "run": { "before": "php artisan migrate --force && php artisan storage:link" } }
{ "run": { "before": "python manage.py migrate --run-syncdb" } }
{ "run": { "before": "npx prisma migrate deploy" } }
{ "run": { "before": "alembic upgrade head" } }
Penting: Jika
run.beforegagal (exit code non-zero), deployment akan dianggap gagal dan pod tidak akan dijalankan. Gunakan|| truedi akhir jika command boleh gagal:{ "run": { "before": "php artisan view:cache || true" } }
run.after#
Command yang dijalankan setelah aplikasi mulai berjalan dan health check pertama berhasil.
{
"run": {
"after": "php artisan queue:restart"
}
}
run.isTcp#
Set ke true jika aplikasi kamu adalah TCP server (bukan HTTP/HTTPS). Health check HTTP akan dinonaktifkan.
{
"run": {
"port": 9000,
"isTcp": true
}
}
Kapan dipakai: Aplikasi WebSocket, gRPC server, database, game server, atau service TCP lainnya. Baca Panduan TCP Mode di Helipod untuk detail.
health: Konfigurasi Health Check#
Helipod secara berkala melakukan HTTP GET ke endpoint health check untuk memastikan pod masih sehat. Jika health check gagal berkali-kali, pod akan di-restart otomatis.
health.path#
Path endpoint health check. Default: /.
{
"health": {
"path": "/api/health"
}
}
Rekomendasi: buat endpoint khusus yang mengecek koneksi database dan dependencies kritis.
Contoh health endpoint untuk Django:
# views.py
from django.http import JsonResponse
from django.db import connection
def health(request):
try:
connection.ensure_connection()
return JsonResponse({"status": "ok", "db": "connected"})
except Exception as e:
return JsonResponse({"status": "error", "detail": str(e)}, status=503)
Contoh untuk NestJS:
@Controller('api/health')
export class HealthController {
@Get()
check() {
return { status: 'ok', timestamp: new Date().toISOString() };
}
}
health.duration#
Waktu tunggu (detik) sebelum Helipod mulai melakukan health check setelah pod start. Default: 15 detik.
{
"health": {
"path": "/health",
"duration": 30
}
}
Kapan dinaikkan: Jika aplikasi kamu butuh waktu lama untuk startup (misalnya loading ML model besar, warming up cache). Set ke waktu yang cukup agar pod tidak di-restart prematur.
volume: Persistent Storage#
Konfigurasi persistent volume yang di-mount ke container. File dalam volume ini tidak hilang saat redeploy.
volume.mountPath#
Path di dalam container tempat volume di-mount.
{
"volume": {
"mountPath": "/app/storage",
"size": 10
}
}
volume.size#
Ukuran volume dalam GB. Default: bergantung plan.
Kapan dipakai:
- Laravel: mount
/var/www/html/storageuntuk uploaded files - Aplikasi yang menyimpan file lokal (uploads, generated PDFs, dll)
- Database SQLite
- Aplikasi yang butuh cache persistent antar restart
Baca Panduan Persistent Volume di Helipod untuk detail.
env: Default Environment Variables#
Set default environment variables yang akan di-inject ke container. Variable yang di-set di tab Variables dashboard akan override nilai di sini.
{
"env": {
"NODE_ENV": "production",
"TZ": "Asia/Jakarta",
"LOG_LEVEL": "info",
"CACHE_TTL": "3600"
}
}
Kapan dipakai: Untuk nilai default yang tidak sensitif. Jangan simpan secret (API key, password) di sini karena helipack.json ada di repository.
spec: Resource Requirements#
Override resource yang dibutuhkan pod. Ini adalah hint untuk Helipod, resource aktual tetap dibatasi oleh plan yang kamu pilih.
{
"spec": {
"cpu": 500,
"memory": 512
}
}
cpu: jumlah vCPU (250, 500, 1000, 2000, dst)memory: RAM dalam MB (256, 512, 1024, 2048, dst)
packages: System Package Tambahan#
Tambahkan package sistem yang tidak tersedia secara default di base image.
packages.apk: Alpine Linux Packages#
Untuk Node.js dan PHP (Alpine-based):
{
"packages": {
"apk": ["ffmpeg", "imagemagick", "wkhtmltopdf", "ghostscript"]
}
}
Contoh use case:
ffmpeg: video/audio processingimagemagick: image manipulationwkhtmltopdf: HTML ke PDFghostscript: PDF processingchromium: headless browser (Puppeteer)
packages.apt: Debian/Ubuntu Packages#
Untuk Python (Debian-based):
{
"packages": {
"apt": ["libpq-dev", "libmagic1", "ffmpeg", "poppler-utils"]
}
}
packages.phpext: PHP Extensions#
Tambahkan PHP extensions menggunakan mlocati/php-extension-installer:
{
"packages": {
"phpext": ["redis", "imagick", "gd", "zip", "intl", "opcache"]
}
}
Extensions yang sudah diinstall by default untuk Laravel: pdo_mysql, pdo_pgsql, mbstring, xml, bcmath, pcntl, intl, zip, sodium.
packages.pecl: PHP PECL Extensions#
{
"packages": {
"pecl": ["redis", "swoole", "imagick"]
}
}
packages.pip: Extra Python Packages#
Packages pip tambahan yang diinstall di atas requirements.txt:
{
"packages": {
"pip": ["torch", "transformers"]
}
}
Kapan dipakai: Untuk packages besar seperti PyTorch yang tidak ingin kamu commit ke requirements.txt karena ukurannya.
Contoh Lengkap per Use Case#
Laravel Production dengan Queue#
{
"run": {
"port": 8000,
"before": "php artisan migrate --force && php artisan config:cache && php artisan route:cache",
"after": "php artisan queue:restart"
},
"health": {
"path": "/",
"duration": 20
},
"volume": {
"mountPath": "/var/www/html/storage",
"size": 10
},
"packages": {
"phpext": ["redis", "gd"],
"apk": ["imagemagick"]
},
"env": {
"TZ": "Asia/Jakarta"
}
}
Next.js dengan Custom Port#
{
"run": {
"port": 3000
},
"health": {
"path": "/api/health",
"duration": 30
},
"env": {
"TZ": "Asia/Jakarta",
"NODE_ENV": "production"
}
}
Django + Celery (tanpa separate worker pod)#
{
"run": {
"port": 8000,
"before": "python manage.py migrate --run-syncdb && python manage.py collectstatic --noinput",
"command": "gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 3 --timeout 120"
},
"health": {
"path": "/health/",
"duration": 25
},
"packages": {
"apt": ["libpq-dev", "ffmpeg"]
}
}
FastAPI ML Model Serving#
{
"run": {
"port": 8000,
"command": "uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1",
"before": "python scripts/download_model.py"
},
"health": {
"path": "/health",
"duration": 60
},
"volume": {
"mountPath": "/app/models",
"size": 20
},
"spec": {
"cpu": 2,
"memory": 4096
},
"packages": {
"pip": ["torch", "transformers", "accelerate"]
}
}
NestJS + Prisma#
{
"run": {
"port": 3000,
"before": "npx prisma migrate deploy",
"command": "node dist/main"
},
"health": {
"path": "/api/health",
"duration": 20
},
"env": {
"NODE_ENV": "production"
}
}
TCP Server (WebSocket / gRPC)#
{
"run": {
"port": 9000,
"isTcp": true,
"command": "node dist/server.js"
}
}
Prioritas Konfigurasi#
Saat ada konflik antara nilai di helipack.json dan konfigurasi di dashboard Helipod, berikut prioritasnya (dari tertinggi ke terendah):
- Dashboard Variables: environment variables yang di-set di tab Variables
- helipack.json
env: default env vars di file konfigurasi - Helipack defaults: nilai bawaan per framework
Ini berarti kamu bisa set nilai default di helipack.json untuk development, lalu override di dashboard untuk production, tanpa ubah kode.
Validasi helipack.json#
Sebelum push ke repository, validasi JSON-mu agar tidak ada syntax error:
# Di terminal local
cat helipack.json | python -m json.tool
# Atau gunakan jq
jq . helipack.json
Syntax error di helipack.json akan menyebabkan Helipack mengabaikan file ini dan menggunakan konfigurasi default, bukan menyebabkan build gagal.
Kesimpulan#
helipack.json adalah cara kamu berbicara langsung ke Helipack, memberi instruksi spesifik tentang bagaimana aplikasimu harus di-build dan dijalankan. Dari yang sederhana seperti custom port, sampai yang kompleks seperti ML model serving dengan GPU, semua bisa dikonfigurasi lewat satu file JSON.
Ingin tahu lebih dalam tentang cara Helipack mendeteksi framework dan menghasilkan Dockerfile? Baca Helipack: Dockerfile Otomatis.
Punya pertanyaan? Hubungi kami di support@helipod.io atau bergabung ke komunitas di hangar.helipod.io.