Fondasi Infrastruktur K8s — Skeleton Django¶
Status: SUDAH DIIMPLEMENTASIKAN (14 Juli 2026)
Berbeda dari halaman-halaman sebelumnya (desain skema di atas kertas), halaman ini
mendokumentasikan infrastruktur nyata yang sudah berjalan — Modul 0/9 (Fondasi) dan
§2 Roadmap ("Fondasi Infrastruktur K8s") sekarang punya skeleton Django yang benar-benar
hidup, terhubung ke appdb, dan bisa diakses publik.
1. Namespace¶
Namespace baru sia-multitenant — terpisah dari demo-app/galera-system/postgres-system
yang sudah ada, sesuai Roadmap §2.
2. Database — Pakai appdb/appuser yang Sudah Ada¶
Sesuai kesimpulan uji isolasi (Skema Data — Fondasi §11):
tidak ada database/role baru dibuat — SIA memakai appdb/appuser yang sudah ada di
postgres-cluster (sebelumnya kosong, belum dipakai apa pun).
Kredensial disalin sebagai Secret di namespace sia-multitenant (bukan referensi cross-namespace
langsung — Secret tidak bisa dibaca lintas-namespace di Kubernetes):
kubectl create secret generic sia-db-credentials -n sia-multitenant \
--from-literal=host=postgres-cluster.postgres-system.svc.cluster.local \
--from-literal=port=5432 \
--from-literal=dbname=appdb \
--from-literal=user=appuser \
--from-literal=password='<disalin dari Secret appuser.postgres-cluster... di postgres-system>'
Pengingat wajib: FORCE ROW LEVEL SECURITY di setiap migrasi
Karena appuser adalah pemilik tabel-tabel yang akan dibuat Django (migrasi berjalan
sebagai appuser), setiap CREATE TABLE wajib diikuti ALTER TABLE ... FORCE ROW LEVEL
SECURITY — bukan cuma ENABLE. Skeleton di halaman ini belum punya tabel aplikasi
(baru migrasi bawaan Django: auth, admin, contenttypes, sessions) sehingga belum
relevan, tapi ini wajib diterapkan begitu model pertama (mis. Tenant, Fakultas) mulai
diimplementasikan sebagai migrasi Django nyata.
3. Struktur Skeleton Django¶
sia-skeleton/
manage.py
core/
settings.py # DATABASES dari env var (Secret), LANGUAGE_CODE = "id"
urls.py # admin, health check, site_header/site_title
wsgi.py
akademik/
apps.py # app kosong, placeholder untuk model Modul 2/3 nanti
migrations/
Belum ada model aplikasi (Tenant, Fakultas, dst. dari skema data) — migrasi yang berjalan
baru migrasi bawaan Django (auth, admin, contenttypes, sessions), membuktikan koneksi ke
appdb bekerja tanpa mengunci desain skema final ke kode terlalu awal.
3.1 Health Check¶
def healthz(request):
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
cursor.fetchone()
db_status = "connected"
except Exception as e:
return JsonResponse({"status": "error", "database": str(e)}, status=503)
return JsonResponse({"status": "ok", "database": db_status})
Dipakai sebagai readinessProbe dan livenessProbe di Deployment — bukan sekadar endpoint
statis, benar-benar menguji konektivitas appdb tiap kali Kubernetes memeriksa kesehatan pod.
4. Deployment — Tanpa Build Image Kustom¶
Pola yang sama seperti status-api dan preview Unfold/Jazzmin sebelumnya — initContainer yang
pip install ke volume bersama, kode aplikasi lewat ConfigMap (di-tar terlebih dahulu supaya
struktur direktori tetap terjaga):
initContainers:
- name: setup
image: python:3.12-slim
command: ['sh', '-c', 'mkdir -p /app && tar xzf /code/app.tar.gz -C /app && pip install --target=/deps --no-cache-dir django psycopg2-binary']
containers:
- name: django
image: python:3.12-slim
command: ['sh', '-c', 'python manage.py migrate --noinput && python manage.py collectstatic --noinput && (python manage.py createsuperuser --noinput --username admin --email admin@oneke.ums.id || true) && python manage.py runserver 0.0.0.0:8000']
readinessProbe: { httpGet: { path: /sia/healthz/, port: 8000 } }
livenessProbe: { httpGet: { path: /sia/healthz/, port: 8000 } }
createsuperuser --noinput dengan || true — aman dijalankan berulang tiap restart pod (gagal
senyap kalau superuser sudah ada dari run sebelumnya, tanpa menghentikan startup).
5. Routing — Path /sia/, Bukan Subdomain Baru¶
Roadmap awal menyebut contoh sia.oneke.ums.id (subdomain). Untuk tahap skeleton ini, dipakai
path /sia/ di domain oneke.ums.id yang sudah ada — konsisten dengan phpMyAdmin/pgAdmin/
Grafana yang sudah lebih dulu memakai pola ini, dan menghindari provisioning DNS/sertifikat baru
untuk sekadar smoke-test infrastruktur.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: sia-skeleton-ingressroute
namespace: sia-multitenant
spec:
entryPoints: [web, websecure]
routes:
- match: Host(`oneke.ums.id`) && PathPrefix(`/sia`)
kind: Rule
priority: 100
services: [{ name: sia-skeleton-svc, port: 8000 }]
tls:
secretName: oneke-root-tls
Pola URL Django mengikuti gaya pgAdmin/Grafana (path lengkap ditulis langsung di urls.py,
STATIC_URL = "/sia/static/") — tanpa stripPrefix, sama seperti alasan yang sudah dibahas
di Instalasi PostgreSQL + Patroni.
Subdomain dedicated tetap bisa ditambahkan nanti
Keputusan path vs subdomain di sini murni soal kemudahan tahap awal — arsitektur multi-tenant
(custom domain per kampus, lihat Keputusan Arsitektur §2) tidak
bergantung pada pilihan ini sama sekali, karena custom domain tenant di-resolve dari Host
header terlepas dari pola akses default yang dipakai tim oneKE sendiri.
6. Label Admin — Bahasa Indonesia¶
admin.site.site_header = "Sistem Informasi Akademik Multi-Tenant"
admin.site.site_title = "SIA Admin"
admin.site.index_title = "Panel Administrasi"
Temuan: Django sudah punya terjemahan Indonesia bawaan
Dengan LANGUAGE_CODE = "id" di settings.py, seluruh teks bawaan admin (label field,
tombol) otomatis diterjemahkan tanpa perlu file terjemahan tambahan — "Username" →
"Nama pengguna", "Password" → "Sandi", "Log in" → "Masuk", dst. Django sendiri sudah
menyertakan berkas .po/.mo Bahasa Indonesia untuk seluruh string bawaannya.
7. Verifikasi¶
| Pemeriksaan | Hasil |
|---|---|
GET /sia/healthz/ |
✅ {"status": "ok", "database": "connected"} |
GET /sia/admin/login/ |
✅ 200, tampil dengan label Indonesia + site_header custom |
Migrasi bawaan Django ke appdb |
✅ Berhasil (auth, admin, contenttypes, sessions) |
| Superuser dibuat | ✅ admin (kredensial di Secret sia-admin-password, tidak dituliskan plaintext di sini) |
8. Ringkasan Kredensial¶
| Secret | Namespace | Isi |
|---|---|---|
sia-db-credentials |
sia-multitenant |
Host/port/dbname/user/password appdb |
sia-django-secret |
sia-multitenant |
SECRET_KEY Django |
sia-admin-password |
sia-multitenant |
Password superuser admin |
kubectl get secret sia-admin-password -n sia-multitenant -o jsonpath='{.data.password}' | base64 -d
9. Langkah Berikutnya¶
Sesuai Roadmap §2, tersisa: runbook custom domain per tenant (§3), lalu integrasi
monitoring & homepage (§4). Implementasi model aplikasi nyata (Tenant, Fakultas, dst. dari
enam halaman skema data) menyusul sebagai pekerjaan pengembangan aplikasi — di luar cakupan
"fondasi infrastruktur" yang selesai di halaman ini.
Kembali ke Roadmap Implementasi atau Skema Data — Fondasi.