Cloud Deployment
Peta platform cloud deployment, deploy ke Railway dan Google Cloud Run, kelola secrets, dan diagnosis empat masalah deployment paling umum.
Image Docker yang sudah dibuat di Bab 16 masih hanya berjalan di mesin lokalmu. Bab ini membahas cara mengirimnya ke cloud agar bisa diakses siapa saja, kapan saja, dan lebih penting dari itu, cara memilih platform deployment yang tepat berdasarkan constraint proyekmu, serta cara menangani masalah yang paling sering muncul saat pertama kali men-deploy ke cloud.
17.1 Peta Platform Cloud Deployment
Ada banyak cara men-deploy aplikasi ke cloud. Sebelum menulis perintah apapun, pahami dulu peta lanskap platform yang tersedia dan trade-off masing-masing, karena pilihan ini akan mempengaruhi cara kerjamu untuk sisa siklus hidup proyek.
17.2 Framework Keputusan: Memilih Platform yang Tepat
| Platform | Kemudahan Setup | Biaya | Skala Otomatis | Terbaik Untuk |
|---|---|---|---|---|
| Railway railway.app | Sangat mudah, connect repo -> deploy | Free tier ada, paid mulai $5/bulan | Ya, otomatis | Prototyping, demo, proyek bootcamp. Deploy dalam hitungan menit. |
| Render render.com | Sangat mudah, connect repo -> deploy | Free tier (spin down saat idle), paid mulai $7/bulan | Ya, otomatis | Proyek serius yang butuh free tier, perlu sabar menunggu wake up. |
| Google Cloud Run cloud.google.com | Sedang, perlu setup GCP project | Bayar per request, sangat murah untuk traffic rendah | Ya, hingga 0 instance saat idle | Produksi dengan traffic tidak menentu. Scale to zero = tidak bayar saat idle. |
| DigitalOcean Droplet | Perlu setup manual: install Docker, nginx, SSL | Mulai $6/bulan untuk server tetap menyala | Tidak, manual | Tim yang butuh kontrol penuh atas server, akses SSH, custom config. |
| AWS ECS / Fargate | Kompleks, banyak konfigurasi IAM, VPC | Bayar per vCPU dan RAM per detik | Ya, sangat fleksibel | Enterprise, tim dengan engineer DevOps dedicated. |
Railway adalah pilihan yang paling cepat untuk membuktikan sistem berjalan di cloud. Setelah itu, Google Cloud Run adalah pilihan yang paling cost-efficient untuk produksi karena scale-to-zero, kamu tidak membayar apapun saat tidak ada traffic.
17.3 Deploy ke Railway
Railway adalah platform yang paling cepat untuk pertama kali mencoba deployment. Tidak perlu memahami konsep cloud yang dalam, cukup Docker yang sudah dibuat di Bab 16.
1. Pastikan Dockerfile dan .dockerignore Sudah Ada
Railway mendeteksi Dockerfile secara otomatis di root repositori.
my-project/
├── Dockerfile
├── .dockerignore
├── requirements.txt
├── main.py
└── .env.example # bukan .env asli!
Railway menyediakan panel untuk mengisi environment variable secara terpisah.
2. Push Kode ke GitHub
Railway terhubung langsung ke repositori GitHub. Setiap push ke branch utama akan otomatis memicu rebuild dan redeploy.
git add .
git commit -m "ready for deployment"
git push origin main
3. Buat Project di Railway dan Connect Repo
Daftar di railway.app, buat project baru, pilih "Deploy from GitHub repo", dan pilih repositori yang sudah berisi Dockerfile. Railway akan langsung mulai membangun image, tanpa perlu konfigurasi tambahan.
4. Tambahkan Environment Variable di Railway Dashboard
Buka tab "Variables" di Railway dashboard dan tambahkan semua environment variable yang ada di file .env lokalmu.
GEMINI_API_KEY=AIzaSy...
PINECONE_API_KEY=pcsk_...
ENVIRONMENT=production
Setelah menambahkan variable, Railway otomatis redeploy. Ini normal, tunggu hingga deployment selesai sebelum mengakses endpoint.
5. Verifikasi Deployment dan Akses Endpoint
Railway menyediakan URL publik otomatis setelah deployment berhasil. Verifikasi dengan mengakses endpoint health check terlebih dahulu.
curl https://rework-api-production.up.railway.app/health
Jika berhasil, akan muncul response JSON: {"status":"ok"}. Selanjutnya, coba endpoint lain seperti /embeddings atau /chat.
17.4 Deploy ke Google Cloud Run
Cloud Run adalah pilihan terbaik untuk produksi: serverless, bayar per request, scale otomatis hingga nol saat tidak ada traffic. Proses deployment melibatkan tiga langkah tambahan dibanding Railway: push image ke registry, lalu deploy dari registry ke Cloud Run.
Setup Awal (Sekali per Mesin)
Instalasi Google Cloud CLI dan autentikasi ke project GCP. Langkah ini hanya dilakukan sekali per mesin.
# Install Google Cloud CLI
# https://cloud.google.com/sdk/docs/install
# Login ke akun Google
gcloud auth login
# Set project GCP yang akan digunakan
gcloud config set project YOUR_PROJECT_ID
# Aktifkan API yang dibutuhkan
gcloud services enable run.googleapis.com
gcloud services enable artifactregistry.googleapis.com
# Buat Artifact Registry untuk menyimpan Docker image
gcloud artifacts repositories create rework-repo \
--repository-format=docker \
--location=asia-southeast1 \
--description="Repository untuk image API ReWork"
# Autentikasi Docker ke Google Artifact Registry
gcloud auth configure-docker asia-southeast1-docker.pkg.dev
Gunakan region asia-southeast1 (Singapura) untuk latensi terendah dari Indonesia.
Build dan Push Image
Build image Docker dan push ke Artifact Registry. Setiap kali kode berubah, ulangi langkah ini lalu deploy ulang.
# Variabel yang akan digunakan berulang
PROJECT_ID="your-project-id"
REGION="asia-southeast1"
IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/rework-repo/rework-api"
# Build image dengan tag versi
docker build -t "${IMAGE}:latest" .
# Push image ke Artifact Registry
docker push "${IMAGE}:latest"
# Verifikasi image berhasil di-push
gcloud artifacts docker images list \
"${REGION}-docker.pkg.dev/${PROJECT_ID}/rework-repo"
Deploy ke Cloud Run
Deploy image yang sudah ada di Artifact Registry ke Cloud Run. Perintah ini bisa dijalankan ulang setiap kali ada image baru, Cloud Run akan otomatis melakukan rolling deployment tanpa downtime.
gcloud run deploy rework-api \
--image "${IMAGE}:latest" \
--platform managed \
--region "${REGION}" \
--port 8000 \
--allow-unauthenticated \
--memory 1Gi \
--cpu 1 \
--min-instances 0 \
--max-instances 10 \
--timeout 60
# Penjelasan flag penting:
# --allow-unauthenticated : endpoint bisa diakses publik
# --memory 1Gi : cukup untuk model embedding lokal
# --min-instances 0 : scale to zero (tidak bayar saat idle)
# --max-instances 10 : batas atas scaling otomatis
# --timeout 60 : maksimal 60 detik per request
# Setelah deploy selesai, Cloud Run menampilkan URL:
# Service URL: https://rework-api-xxxx-as.a.run.app
curl https://rework-api-xxxx-as.a.run.app/health
Kelola Secrets
Cara yang benar untuk mengelola API key dan secret di Cloud Run, menggunakan Google Secret Manager, bukan menyimpannya langsung di environment variable yang kurang aman.
# Cara 1: Environment variable langsung (lebih sederhana)
# Cocok untuk secret yang tidak terlalu sensitif
gcloud run services update rework-api \
--region "${REGION}" \
--set-env-vars "GEMINI_API_KEY=your-key-here,ENVIRONMENT=production"
# Cara 2: Google Secret Manager (lebih aman)
# Cocok untuk API key produksi yang sensitif
# Buat secret di Secret Manager
echo -n "your-gemini-key" | gcloud secrets create gemini-api-key \
--data-file=-
echo -n "your-pinecone-key" | gcloud secrets create pinecone-api-key \
--data-file=-
# Deploy dengan referensi ke Secret Manager
gcloud run deploy rework-api \
--image "${IMAGE}:latest" \
--region "${REGION}" \
--set-secrets "GEMINI_API_KEY=gemini-api-key:latest" \
--set-secrets "PINECONE_API_KEY=pinecone-api-key:latest"
# Secret otomatis diinjeksikan sebagai environment variable
# saat container start, kode Python tetap menggunakan
# os.getenv("GEMINI_API_KEY") seperti biasa
17.5 Masalah Paling Umum Saat Pertama Kali Deploy
Deployment ke cloud hampir selalu menghasilkan error yang tidak pernah muncul di lokal. Bukan karena kodenya salah, tapi karena ada perbedaan lingkungan yang tidak terlihat. Kenali empat pola masalah yang paling sering terjadi.
1. Container Langsung Exit Setelah Start (Exit Code 1)
Penyebab umum: environment variable tidak terbaca, aplikasi crash saat startup karena variabel wajib seperti API key tidak tersedia. Atau perintah CMD di Dockerfile salah.
Solusi: baca log deployment, pesan error ada di sana.
# Railway: lihat di tab Deployments -> Logs
# Cloud Run:
gcloud run services logs read rework-api --region asia-southeast1
# Pastikan semua env var sudah diisi di dashboard
2. Port Tidak Bisa Diakses dari Luar (Connection Refused)
Penyebab umum: aplikasi berjalan di 127.0.0.1 (localhost), hanya bisa diakses dari dalam container itu sendiri. Atau port yang dibuka aplikasi tidak sesuai dengan yang dikonfigurasi di platform.
Solusi: ganti host ke 0.0.0.0 dan pastikan port konsisten di Dockerfile, aplikasi, dan konfigurasi platform.
# Di main.py atau Dockerfile CMD:
uvicorn main:app --host 0.0.0.0 --port 8000
# Di Cloud Run, pastikan flag --port 8000
# sesuai dengan port yang digunakan aplikasi
3. Build Berhasil Tapi Request Timeout (503 / 504)
Penyebab umum: model embedding atau proses berat dijalankan saat startup (bukan saat pertama dibutuhkan), menyebabkan container butuh waktu lama untuk siap menerima request. Atau memory container tidak cukup.
Solusi: lazy loading, inisialisasi model hanya saat pertama kali dibutuhkan.
# Buruk: load model saat module diimpor
model = SentenceTransformer("...") # di level modul
# Baik: lazy loading
_model = None
def get_model():
global _model
if _model is None:
_model = SentenceTransformer("...")
return _model
4. Berjalan di Lokal, Error di Cloud (Platform Mismatch)
Penyebab umum: laptop menggunakan chip ARM (Apple Silicon M1/M2) tapi cloud menggunakan arsitektur AMD64. Image Docker yang dibangun di M1 tidak bisa berjalan di server Linux AMD64 tanpa flag khusus.
Solusi: selalu build image untuk arsitektur AMD64 saat akan dideploy ke cloud, terlepas dari arsitektur laptop yang digunakan.
# Build untuk cloud (AMD64) dari M1/M2:
docker buildx build \
--platform linux/amd64 \
-t rework-api .
# Atau tambahkan di Dockerfile:
FROM --platform=linux/amd64 python:3.11-slim
Kesalahan Umum
Secret yang tersimpan di image bisa diekstrak oleh siapa saja yang memiliki akses ke image tersebut. Secret di kode yang di-push ke GitHub akan terekspos ke seluruh dunia, bahkan setelah dihapus, riwayat commit masih menyimpannya. Selalu gunakan Secret Manager (Cloud Run) atau panel environment variable dari platform deployment.
Ketika deployment gagal, reflex pertama biasanya mengubah kode atau konfigurasi. Tapi tanpa membaca log terlebih dahulu, kamu tidak tahu apa yang sebenarnya salah dan bisa menghabiskan waktu mengubah hal yang tidak relevan. Baca log dulu, identifikasi baris error yang spesifik, baru putuskan apa yang perlu diubah.
Ini adalah salah satu penyebab paling umum dari "works on my machine but fails in cloud" yang spesifik untuk pengguna Mac modern. Jadikan ini bagian dari workflow build standar sejak awal, jangan menunggu sampai deployment pertama gagal.
Setiap kali deploy ke environment baru, tes pertama yang harus dilakukan adalah memanggil /health. Jika endpoint ini merespons, server berjalan, port terbuka, dan routing bekerja. Jika tidak, masalah ada di infrastruktur, bukan di logika AI, ini mempersempit area diagnosis secara signifikan.
Railway menghilangkan semua kompleksitas cloud sehingga kamu bisa fokus memastikan aplikasi berjalan dengan benar. Setelah sistem terbukti berjalan, migrasi ke Cloud Run proses yang melibatkan perintah yang sudah dibahas di bab ini dan tidak memerlukan perubahan kode apapun.
Ringkasan Bab 17
- Saya memahami perbedaan antara PaaS (Railway/Render), Container Service (Cloud Run), dan IaaS (VPS), serta kapan masing-masing tepat digunakan.
- Saya bisa men-deploy aplikasi FastAPI yang sudah di-Dockerize ke Railway: push ke GitHub, connect repo, dan mengisi environment variable di dashboard.
- Saya bisa melakukan siklus deploy ke Google Cloud Run: build image, push ke Artifact Registry, dan deploy dengan konfigurasi yang tepat termasuk port dan memory.
- Saya menggunakan Secret Manager atau panel environment variable platform, tidak pernah menyimpan API key di dalam image Docker atau di kode yang di-push ke GitHub.
- Saya bisa mendiagnosis empat masalah deployment paling umum: container exit, port tidak bisa diakses, request timeout, dan platform mismatch (ARM vs AMD64).
- Jika menggunakan Apple Silicon (M1/M2), saya selalu menggunakan flag --platform linux/amd64 saat build image untuk deployment ke cloud.
- Saya menggunakan lazy loading untuk model yang berat, menginisialisasi model hanya saat pertama kali dibutuhkan, bukan saat startup container.