On Premise Kubernetes

Runbook instalasi AlurKerja di cluster Kubernetes on-premise. Berurutan 1..47, satu nomor satu aksi, setiap langkah memiliki validasi observable.

A. Ringkasan & Definition of Done

Panduan ini membantu tim ops menginstal AlurKerja di cluster Kubernetes on-premise milik pelanggan. Runbook ini sudah teruji pada deployment Linknet (PoC LPP) dan dirancang ulang sebagai dokumen one-shot read: satu kali baca dan langsung dapat dieksekusi tanpa perlu sumber tambahan.

Definition of Done — instalasi dianggap selesai bila:

  • Semua deployment AlurKerja (17 workload) dalam state Available dan pod-nya Ready.
  • Endpoint frontend (App, Studio, Compro, Simulation), Camunda web, dan API gateway merespons dengan HTTP 200 / 30x sesuai konvensi.
  • Pengguna admin pertama berhasil login dan membuat tenant.
  • Logbook instalasi terisi lengkap dan ditandatangani implementor + reviewer.

Estimasi waktu eksekusi: 4–6 jam untuk tim ops yang akrab dengan kubectl (di luar waktu siapkan data prasyarat).

Sebelum mulai, download template logbook: alurkerja-install-k8s-checklist.xlsx. File ini sinkron 1:1 dengan nomor langkah di halaman ini — isi sambil eksekusi sebagai bukti audit dan referensi untuk instalasi berikutnya.

B. Prasyarat

Langkah 1–7 memastikan environment siap. Hentikan dan perbaiki bila ada langkah yang gagal — jangan lanjut sebelum prasyarat terpenuhi.

1. Verifikasi kubectl terpasang

Aksi

kubectl version --client --output=yaml

Expected output

Menampilkan clientVersion dengan gitVersion: v1.27.x atau lebih baru.

Jika gagal: jika kubectl tidak terpasang, install dulu sesuai distro (brew install kubectl, apt install kubectl, dll).

2. Verifikasi context cluster aktif

Aksi

kubectl config current-context

Expected output

Nama context yang menunjuk ke cluster target pelanggan (bukan docker-desktop atau cluster development pribadi).

nama context mengandung identifier cluster pelanggan (contoh linknet-prod, acme-staging).

Jika gagal: jika salah, pindah context dengan kubectl config use-context <NAMA_CONTEXT>.

3. Verifikasi permission namespace

Aksi

kubectl auth can-i create namespace
kubectl auth can-i create deployment --namespace <CALON_NAMESPACE>
kubectl auth can-i create secret    --namespace <CALON_NAMESPACE>

Expected output

Tiga baris yes.

Jika gagal: jika ada no, minta cluster-admin untuk grant role (cluster-admin atau RBAC custom yang setara).

4. Verifikasi Ingress Controller tersedia

Aksi

kubectl get pods --all-namespaces \
  -l app.kubernetes.io/name=ingress-nginx

Expected output

Minimal satu pod controller dalam state Running.

kolom STATUS = Running, READY = 1/1.

Jika gagal: jika Ingress Controller belum ada, install Nginx Ingress Controller sebelum lanjut. AlurKerja saat ini diuji dengan ingress-nginx; controller lain (Traefik, HAProxy) belum divalidasi.

5. Verifikasi konektivitas PostgreSQL

Aksi

Dari mesin yang akan dipakai eksekusi (atau pod debug di cluster):

psql "postgresql://<DB_USER>:<DB_PASSWORD>@<DB_HOST>:<DB_PORT>/<DB_NAME>" \
  -c "SELECT version();"

Expected output

Banner PostgreSQL versi 13 atau lebih baru.

Jika gagal: jika koneksi gagal, cek firewall, security group, atau routing dari cluster ke host database. PostgreSQL boleh di luar cluster (managed service, VM terpisah) atau di dalam cluster.

6. Verifikasi DNS mengarah ke Ingress

Aksi

Dari mesin di luar cluster:

dig +short <APP_FE_HOST>
dig +short <API_HOST>

Expected output

IP yang sama dengan address Ingress Controller (cek kubectl -n ingress-nginx get svc).

IP hasil dig cocok dengan EXTERNAL-IP dari LoadBalancer Ingress, atau NodePort yang ter-publish.

Jika gagal: jika DNS belum mengarah, koordinasi dengan tim network pelanggan. DNS boleh belum siap saat eksekusi langkah ini — tapi harus siap sebelum smoke test (Step 39–41).

7. Verifikasi akses Harbor registry

Aksi

docker login harbor.merapi.javan.id

Expected output

Login Succeeded.

Jika gagal: kalau gagal, minta credential Harbor ke tim Javan (registry image AlurKerja terpusat di harbor.merapi.javan.id). Credential ini akan dipakai untuk Step 10.

C. Arsitektur Ringkas

AlurKerja terdiri dari 17 workload yang berjalan di Kubernetes:

  • 1 cacheredis (in-cluster, untuk session + cache aplikasi).
  • 11 backend Goonprem-auth, onprem-bpm, onprem-tenant, onprem-compro-be, onprem-notification, onprem-integration, onprem-report, onprem-generate-test, onprem-proxy, onprem-migration, onprem-simulation-be.
  • 1 backend Java (Camunda)onprem-camunda, mesin BPMN/workflow engine.
  • 4 frontendonprem-app-fe, onprem-studio-fe, onprem-compro-fe, onprem-simulation-fe.

Jika diagram di atas tidak ter-render (masih tampak sebagai code block atau pesan error), build belum punya mermaid di dependency atau wrapper <Mermaid> belum terdaftar di mdx-components.tsx. Versi statik PNG tersedia di Lotus /architecture.

D. Persiapan Cluster

Langkah 8–12 menyiapkan namespace dan secret registry untuk pull image dari Harbor.

8. Set variabel instalasi

Aksi

export NAMESPACE="alurkerja"
export KUSTOMIZE_DIR="k8s"

Sesuaikan NAMESPACE dengan konvensi pelanggan (alurkerja-prod, acme-staging, dst). KUSTOMIZE_DIR mengikuti path manifest di repo alurkerja/on-premises.

Override namespace di manifest. Manifest di branch feat/k8s-poc-manifests meng-hardcode namespace: poc-lpp di setiap file (warisan PoC Linknet). kustomization.yaml belum punya directive namespace: global. Sebelum lanjut ke Step 9, tambahkan baris berikut di k8s/kustomization.yaml:

namespace: ${NAMESPACE}

(Atau alternatif manual: find k8s/ -name "*.yaml" -exec sed -i.bak "s/namespace: poc-lpp/namespace: ${NAMESPACE}/g" {} \;.)

Expected output

Tidak ada — assignment env var.

echo $NAMESPACE $KUSTOMIZE_DIR menampilkan nilai yang baru di-set. grep -c 'namespace: poc-lpp' k8s/**/*.yaml = 0.

Perhatian: jangan lanjut ke step 9 sebelum kedua env var ter-set dan namespace di manifest sudah di-override, karena semua command berikutnya bergantung pada keduanya.

9. Buat namespace target

Aksi

kubectl create namespace ${NAMESPACE} \
  --dry-run=client -o yaml | kubectl apply -f -

Expected output

namespace/<NAMESPACE> created

atau, jika sudah ada:

namespace/<NAMESPACE> configured

kubectl get namespace ${NAMESPACE} menampilkan namespace dengan status Active.

Perhatian: pakai pattern --dry-run=client -o yaml | kubectl apply -f - supaya idempoten — boleh dijalankan ulang tanpa error.

10. Buat secret registry Harbor

Aksi

kubectl -n ${NAMESPACE} create secret docker-registry harbor-regcred \
  --docker-server=harbor.merapi.javan.id \
  --docker-username='<HARBOR_USERNAME>' \
  --docker-password='<HARBOR_PASSWORD>' \
  --dry-run=client -o yaml | kubectl apply -f -

Expected output

secret/harbor-regcred created

kubectl -n ${NAMESPACE} get secret harbor-regcred menampilkan secret dengan TYPE kubernetes.io/dockerconfigjson.

Perhatian: jangan ketik password di shell history yang ter-save. Gunakan variabel env atau read dari file .env lokal dengan chmod 600.

11. Validasi secret registry dapat dipakai

Aksi

kubectl -n ${NAMESPACE} get secret harbor-regcred -o jsonpath='{.data.\.dockerconfigjson}' \
  | base64 -d \
  | jq -r '.auths | keys[]'

Expected output

harbor.merapi.javan.id

server registry sesuai (bukan registry lain).

Jika gagal: jika output kosong atau salah server, hapus secret (kubectl -n ${NAMESPACE} delete secret harbor-regcred) dan ulang Step 10.

12. Verifikasi clone repo manifest

Aksi

git clone git@gitlab.javan.co.id:alurkerja/on-premises.git
cd on-premises
git checkout feat/k8s-poc-manifests

Expected output

Repo terdownload dan branch feat/k8s-poc-manifests aktif. Working directory berisi folder k8s/, config/, nginx/, dsb.

ls k8s/config/ menampilkan configmap.yaml, secrets.yaml, camunda-configmap.yaml. ls k8s/apps/ menampilkan 17 file deployment (redis.yaml + 11 onprem-*-be/-auth/... + onprem-camunda.yaml + 4 onprem-*-fe.yaml).

Jika gagal: jika tidak ada akses, minta read access ke tim Javan melalui helpdesk.alurkerja.com. Branch feat/k8s-poc-manifests adalah snapshot manifest hasil PoC Linknet — jadi referensi proven untuk instalasi pertama.

E. ConfigMap & Secret

Langkah 13–22 mengisi semua placeholder konfigurasi. Bagian ini paling rawan kesalahan — patuhi urutan dan validasi tiap langkah.

Jangan commit nilai rahasia asli. Edit file k8s/config/secrets.yaml di working copy lokal, tapi jangan git add setelah diisi nilai produksi. Pakai branch lokal sementara atau template .env di-mount sebagai secret.

13. Edit alurkerja-config

Aksi

$EDITOR k8s/config/configmap.yaml

Isi seluruh placeholder <YOUR_*> mengikuti tabel berikut. Daftar key di bawah cocok dengan manifest feat/k8s-poc-manifests di repo alurkerja/on-premises (22 key total):

KeyNilaiCatatan
DB_HOSThostname PostgreSQLWajib
DB_PORT5432Default PostgreSQL
DB_USERuser database AlurKerjaWajib
DB_NAMEnama databaseWajib
DB_SCHEMApublicDefault; jangan ubah kecuali ada keperluan khusus
KEYCLOAK_URLURL Keycloak SSOKosongkan kalau SSO belum aktif
KEYCLOAK_REALMrealm KeycloakContoh: alurkerja-prod
KEYCLOAK_CLIENTclient ID KeycloakDefault: onprem-client
MINIO_ENDPOINTendpoint MinIOContoh: minio.acme.local:9000
MINIO_BUCKET_NAMEbucket untuk file tenantDefault: tenant-uploads
MINIO_USE_SSLtrue / falsefalse jika MinIO tanpa TLS
STORAGE_PROVIDERminioDefault; alternatif: s3
REDIS_HOSTredisJangan ubah jika pakai Redis dari manifest
REDIS_PORT6379Default Redis
REDIS_PASSWORD(kosong)Isi kalau Redis butuh auth
REDIS_DB0Database Redis untuk session
CACHE_PROVIDERredisDefault
CACHE_ENABLEDtrue
CACHE_HOSTredisSama dengan REDIS_HOST
CACHE_PORT6379Sama dengan REDIS_PORT
CACHE_PASSWORD(kosong)
CACHE_DB0Database Redis untuk cache (boleh sama dengan REDIS_DB)

URL frontend publik (app.{domain}, studio.{domain}, compro.{domain}, simulation.{domain}, api.{domain}, camunda.{domain}) tidak di-config di sini — host publik di-set di Ingress (Step 16). Setiap service backend tahu host-nya sendiri via routing Nginx Ingress Controller. Frontend service mendapat URL via env build-time mereka sendiri (.env.onprem-*-fe).

Expected output

File tersimpan tanpa placeholder <YOUR_*> tersisa.

grep -n '<YOUR_' k8s/config/configmap.yaml tidak menemukan baris (exit code 1).

Perhatian: ConfigMap visible di cluster — pastikan nilai yang ditaruh di sini bukan rahasia. Rahasia masuk ke alurkerja-secrets (Step 14).

14. Edit alurkerja-secrets

Aksi

$EDITOR k8s/config/secrets.yaml

Isi placeholder mengikuti tabel (8 key dari manifest feat/k8s-poc-manifests):

KeyNilaiCatatan
DB_PASSWORDpassword user databaseWajib
DB_PASSpassword user databaseDuplikat dari DB_PASSWORD — diperlukan oleh sebagian service yang masih pakai nama lama
KEYCLOAK_CLIENT_SECRETclient secret KeycloakWajib jika SSO aktif
MINIO_ACCESS_KEYaccess key MinIOWajib
MINIO_SECRET_KEYsecret key MinIOWajib
JWT_SECRETrandom string ≥ 64 charGenerate dengan openssl rand -hex 64
JWT_REFRESH_TOKEN_SECRETrandom string ≥ 64 charBerbeda dari JWT_SECRET
TENANT_SETTINGS_ENCRYPTION_KEY32-byte keyGenerate dengan openssl rand -hex 32
TENANT_SETTINGS_ENCRYPTION_IV16-byte IVGenerate dengan openssl rand -hex 16

Expected output

File tersimpan tanpa placeholder <YOUR_*> tersisa.

grep -n '<YOUR_' k8s/config/secrets.yaml tidak menemukan baris.

Perhatian: wajib git update-index --assume-unchanged k8s/config/secrets.yaml atau pakai branch lokal .gitignored supaya nilai asli tidak ter-commit. Generate JWT_* dan TENANT_SETTINGS_* dengan openssl rand — jangan reuse string yang pernah dipakai di environment lain.

15. Edit camunda-config

Aksi

$EDITOR k8s/config/camunda-configmap.yaml

Berbeda dengan alurkerja-config yang berbentuk key-value pairs, camunda-config berisi satu key application.yaml yang isinya konfigurasi Spring Boot multi-line. Edit field di dalam blob tersebut, bukan menambah top-level key baru.

Field yang wajib di-override (jangan biarkan default placeholder Linknet):

spring:
  minio:
    url: <MINIO_URL>          # contoh: http://minio.acme.local:9000
    accessKey: <MINIO_ACCESS_KEY>
    secretKey: <MINIO_SECRET_KEY>
  datasource:
    hikari:
      schema: camunda          # jangan ubah
    url: jdbc:postgresql://<DB_HOST>:<DB_PORT>/<DB_NAME>?autoReconnect=true
    username: <DB_USER>
    password: <DB_PASSWORD>
camunda.bpm.admin-user:
  id: admin
  password: <CAMUNDA_ADMIN_PASSWORD>  # JANGAN biarkan "admin" di production

Manifest default repo mencantumkan beberapa kredensial development dengan literal string (Telegram bot token, FreeIPA password, dst) sebagai default ${VAR:default}. Override semua default dengan env yang benar atau hapus default sebelum apply ke production.

Expected output

File tersimpan dengan field datasource.url, datasource.username, datasource.password, minio.* sudah berisi nilai environment target.

grep -nE 'admin|asdf1234|J4v4nDev|dummy\.local|merapi\.javan\.id' k8s/config/camunda-configmap.yaml tidak menampilkan baris yang berisi nilai default Linknet/dev.

Perhatian: schema database Camunda harus camunda (matching Step 24 schema init). Kalau di-override ke schema lain, schema SQL Step 24 perlu disesuaikan.

16. Sesuaikan host Ingress

Aksi

$EDITOR k8s/ingress/ingress.yaml      # backend + Camunda (api., simulation., camunda.)
$EDITOR k8s/ingress/ingress-fe.yaml   # frontend (app., studio., compro., simulation.)

Ganti seluruh *-lpp.merapi.javan.id (host Linknet) dengan host pelanggan. Total 7 host yang perlu diganti:

  • api-lpp.merapi.javan.idapi.{domain} (di ingress.yaml)
  • simulation-lpp.merapi.javan.idsimulation.{domain} (di ingress.yaml, untuk simulation-be)
  • camunda-lpp.merapi.javan.idcamunda.{domain} (di ingress.yaml)
  • app-lpp.merapi.javan.idapp.{domain} (di ingress-fe.yaml)
  • studio-lpp.merapi.javan.idstudio.{domain} (di ingress-fe.yaml)
  • compro-lpp.merapi.javan.idcompro.{domain} (di ingress-fe.yaml)
  • simulation-lpp.merapi.javan.idsimulation.{domain} (di ingress-fe.yaml, frontend)

Expected output

Semua host di kedua file Ingress sudah mengarah ke domain pelanggan.

grep -rE 'lpp\.merapi\.javan\.id|dummy\.local' k8s/ingress/ tidak menemukan baris.

Perhatian: kalau pelanggan pakai sub-path (bukan sub-domain), Ingress butuh anotasi nginx.ingress.kubernetes.io/rewrite-target dan struktur path-based — koordinasi dengan tim AlurKerja sebelum custom. Annotation nginx.ingress.kubernetes.io/proxy-body-size: 50m sudah di-set di template untuk file upload tenant.

17. Validasi kelengkapan key alurkerja-config

Aksi

kubectl kustomize ${KUSTOMIZE_DIR} \
  | yq 'select(.kind == "ConfigMap" and .metadata.name == "alurkerja-config") | .data | keys | length'

Expected output

22 (jumlah key sesuai tabel Step 13).

Jika gagal: kalau jumlah kurang, kembali ke Step 13 dan tambahkan key yang missing.

18. Validasi kelengkapan key alurkerja-secrets

Aksi

kubectl kustomize ${KUSTOMIZE_DIR} \
  | yq 'select(.kind == "Secret" and .metadata.name == "alurkerja-secrets") | .stringData | keys | length'

Expected output

9 (jumlah key sesuai tabel Step 14: 8 fungsional + DB_PASS duplikat untuk service yang masih pakai nama lama).

Jika gagal: kalau jumlah kurang, kembali ke Step 14 dan tambahkan.

19. Validasi camunda-config parseable

Aksi

kubectl kustomize ${KUSTOMIZE_DIR} \
  | yq 'select(.kind == "ConfigMap" and .metadata.name == "camunda-config") | .data."application.yaml"' \
  | yq '.spring.datasource.url, .spring.datasource.username, .camunda.bpm.database.schema-name'

Expected output

Tiga baris berurutan: JDBC URL valid, username database, dan camunda.

schema-name tepat camunda; url mengandung <DB_HOST> yang sudah di-set, bukan 192.168.88.100 (alamat dev internal).

Jika gagal: kalau yq gagal parse, blob application.yaml punya YAML error — buka file ulang dan perbaiki indentasi.

20. Render manifest awal untuk validasi placeholder

Aksi

kubectl kustomize ${KUSTOMIZE_DIR} > /tmp/alurkerja-render.yaml

Expected output

File /tmp/alurkerja-render.yaml tersimpan (size > 100 KB tipikal).

ls -la /tmp/alurkerja-render.yaml menampilkan file dengan ukuran > 50 KB.

Jika gagal: kalau kustomize error, baca pesan error dan perbaiki — biasanya karena indentasi atau key tidak valid di file yang di-edit di Step 13–16.

21. Validasi tidak ada placeholder tersisa

Aksi

grep -nE '<YOUR_|dummy\.local|api-lpp\.merapi\.javan\.id|app-lpp\.merapi\.javan\.id|studio-lpp\.merapi\.javan\.id|compro-lpp\.merapi\.javan\.id|simulation-lpp\.merapi\.javan\.id|camunda-lpp\.merapi\.javan\.id' \
  /tmp/alurkerja-render.yaml

Expected output

Tidak ada baris yang cocok (exit code 1).

Jika gagal: kalau masih ada placeholder, hentikan proses dan kembali ke Step 13–16 untuk mengganti. Jangan apply manifest yang masih ada placeholder.

22. Verifikasi tidak ada secret value asli yang akan di-commit

Aksi

git status
git diff --cached k8s/config/secrets.yaml

Expected output

k8s/config/secrets.yaml tidak muncul di "Changes to be committed".

Jika gagal: kalau ter-stage, git restore --staged k8s/config/secrets.yaml. Pertimbangkan pakai .gitignore lokal atau git update-index --assume-unchanged supaya tidak terulang.

F. Schema Camunda

Langkah 23–25 menyiapkan schema database untuk Camunda BPMN engine.

23. Inisialisasi schema dasar

Aksi

psql "postgresql://<DB_USER>:<DB_PASSWORD>@<DB_HOST>:<DB_PORT>/<DB_NAME>" \
  -v ON_ERROR_STOP=1 \
  -f config/init-db.sql

Expected output

Beberapa baris CREATE TABLE, CREATE INDEX, tanpa error.

exit code 0 (echo $? menampilkan 0).

Perhatian: flag -v ON_ERROR_STOP=1 memastikan script berhenti pada error pertama, bukan continue dengan error tersembunyi.

24. Inisialisasi schema Camunda

Aksi

psql "postgresql://<DB_USER>:<DB_PASSWORD>@<DB_HOST>:<DB_PORT>/<DB_NAME>" \
  -v ON_ERROR_STOP=1 \
  -f config/camunda_schema.sql

Expected output

Banyak baris CREATE TABLE camunda.act_* (Camunda 7 punya ~50 table).

exit code 0.

Perhatian: file ini di-maintain oleh upstream Camunda, jangan modifikasi — kalau gagal, biasanya karena schema camunda sudah ada (dari instalasi sebelumnya). Drop schema dengan DROP SCHEMA camunda CASCADE; lalu ulang.

25. Validasi table Camunda tersedia

Aksi

psql "postgresql://<DB_USER>:<DB_PASSWORD>@<DB_HOST>:<DB_PORT>/<DB_NAME>" \
  -c "\dt camunda.*"

Expected output

Daftar minimal 40+ table dengan prefix act_ (act_ru_, act_re_, act_hi_, act_id_, dst).

baris terakhir output menampilkan (NN rows) dengan NN ≥ 40.

Jika gagal: kalau jumlah row jauh lebih sedikit, schema tidak lengkap — drop schema dan ulang Step 24.

G. Render & Apply Manifest

Langkah 26–32 men-deploy seluruh workload AlurKerja ke cluster.

26. Render manifest final

Aksi

kubectl kustomize ${KUSTOMIZE_DIR} > /tmp/alurkerja-render.yaml

Expected output

File ter-render (sama dengan Step 20, tapi setelah semua perbaikan dari Step 21).

wc -l /tmp/alurkerja-render.yaml menampilkan baris > 1000.

Jika gagal: kalau berbeda ukuran signifikan dengan Step 20, kemungkinan ada perubahan struktur — review git diff di working copy.

27. Validasi resource kinds di hasil render

Aksi

grep -cE '^kind: ConfigMap'  /tmp/alurkerja-render.yaml
grep -cE '^kind: Secret'     /tmp/alurkerja-render.yaml
grep -cE '^kind: Deployment' /tmp/alurkerja-render.yaml
grep -cE '^kind: Service'    /tmp/alurkerja-render.yaml
grep -cE '^kind: Ingress'    /tmp/alurkerja-render.yaml

Expected output

ConfigMap:  ≥ 3
Secret:     ≥ 2
Deployment: 17
Service:    ≥ 17
Ingress:    ≥ 1

angka Deployment = 17 (sesuai daftar workload di Section C).

Jika gagal: kalau jumlah Deployment kurang dari 17, ada workload yang missing — review k8s/kustomization.yaml.

28. Validasi namespace di hasil render

Aksi

grep -n 'namespace:' /tmp/alurkerja-render.yaml | sort -u | head

Expected output

Semua resource di-namespace dengan ${NAMESPACE} yang sama (atau tanpa namespace untuk cluster-scoped).

tidak ada namespace lain selain target (alurkerja, atau apapun yang di-set di Step 8).

Jika gagal: kalau ada resource cross-namespace, ada bug di overlay kustomize — minta bantuan tim AlurKerja.

29. Apply manifest ke cluster

Aksi

kubectl apply -k ${KUSTOMIZE_DIR}

Expected output

Banyak baris <resource>/<name> created atau configured.

tidak ada baris yang mengandung error atau Error.

Jika gagal: kalau ada error parsial, baca pesan dan ulang kubectl apply -k setelah perbaikan — apply bersifat idempoten.

30. Validasi ConfigMap + Secret applied

Aksi

kubectl -n ${NAMESPACE} get configmap
kubectl -n ${NAMESPACE} get secret

Expected output

ConfigMap: alurkerja-config, camunda-config (minimal). Secret: alurkerja-secrets, harbor-regcred (minimal).

semua resource ada di output dengan AGE > 0.

Jika gagal: kalau ada yang missing, ulang Step 29 — kemungkinan partial apply.

31. Validasi Deployment + Service applied

Aksi

kubectl -n ${NAMESPACE} get deploy
kubectl -n ${NAMESPACE} get svc

Expected output

17 baris Deployment, ≥ 17 baris Service.

kolom READY Deployment masih 0/N di tahap ini (karena pod sedang scheduled) — itu normal.

Jika gagal: kalau jumlah deploy < 17, ulang Step 29.

32. Validasi Ingress applied

Aksi

kubectl -n ${NAMESPACE} get ingress -o wide

Expected output

Minimal 1 Ingress dengan kolom HOSTS berisi domain pelanggan dan ADDRESS berisi IP Ingress Controller.

kolom HOSTS cocok dengan yang di-set di Step 16.

Perhatian: kolom ADDRESS boleh kosong sementara — biasanya terisi setelah Ingress Controller reconcile (1–2 menit).

H. Verifikasi

Langkah 33–42 memastikan seluruh workload Ready dan endpoint merespons. Bagian ini paling lama karena menunggu image pull + startup probe.

33. Rollout status Redis

Aksi

kubectl -n ${NAMESPACE} rollout status deploy/redis --timeout=5m

Expected output

deployment "redis" successfully rolled out

Perhatian: Redis adalah dependency pertama — kalau gagal, semua service yang butuh cache juga akan gagal. Selesaikan dulu sebelum lanjut.

34. Rollout status backend Go (11 service)

Aksi

for svc in onprem-auth onprem-bpm onprem-tenant onprem-compro-be \
           onprem-notification onprem-integration onprem-report \
           onprem-generate-test onprem-proxy onprem-migration \
           onprem-simulation-be; do
  kubectl -n ${NAMESPACE} rollout status deploy/$svc --timeout=10m
done

Expected output

11 baris "successfully rolled out".

Jika gagal: kalau ada yang stuck ImagePullBackOff, kembali ke Step 11 (validasi Harbor secret). Kalau stuck CrashLoopBackOff, cek log: kubectl -n ${NAMESPACE} logs <POD> --tail=100.

35. Rollout status Camunda

Aksi

kubectl -n ${NAMESPACE} rollout status deploy/onprem-camunda --timeout=10m

Expected output

deployment "onprem-camunda" successfully rolled out

Perhatian: Camunda startup paling lambat (60–120 detik) karena bootstrap engine. Kalau timeout di 10 menit, cek log untuk error koneksi DB atau schema.

36. Rollout status frontend (4 service)

Aksi

for svc in onprem-app-fe onprem-studio-fe onprem-compro-fe onprem-simulation-fe; do
  kubectl -n ${NAMESPACE} rollout status deploy/$svc --timeout=5m
done

Expected output

4 baris "successfully rolled out".

Perhatian: frontend AlurKerja adalah container Nginx serving static asset Next.js — startup cepat (< 30 detik).

37. Validasi semua pod Ready

Aksi

kubectl -n ${NAMESPACE} get pods

Expected output

Semua pod kolom READY menampilkan 1/1 (atau N/N untuk pod multi-container), STATUS Running, RESTARTS = 0.

tidak ada pod dengan status Pending, ImagePullBackOff, CrashLoopBackOff, atau Error.

Jika gagal: kalau ada pod yang RESTARTS > 0, cek log untuk error yang mungkin sudah recoverable. Kalau pod terus restart, hentikan dan investigate sebelum lanjut.

38. Validasi Camunda readiness probe

Aksi

kubectl -n ${NAMESPACE} port-forward deploy/onprem-camunda 8080:8080 &
sleep 3
curl -sI http://localhost:8080/engine-rest/engine
kill %1

Expected output

HTTP/1.1 200 OK dengan body JSON [{"name":"default"}].

Jika gagal: kalau 503 atau timeout, schema Camunda mungkin belum lengkap — ulang Step 24–25.

39. Smoke test App FE

Aksi

curl -ILk https://<APP_FE_HOST>/

Expected output

HTTP 200 (atau 30x redirect ke /login).

kode status 200 atau 30x; header Server menyebut nginx.

Jika gagal: kalau 404, cek Ingress host (Step 16 + 32). Kalau timeout, cek DNS (Step 6).

40. Smoke test Studio FE, Compro FE, Simulation FE

Aksi

curl -ILk https://<STUDIO_FE_HOST>/
curl -ILk https://<COMPRO_FE_HOST>/
curl -ILk https://<SIMULATION_FE_HOST>/

Expected output

Tiga response 200 atau 30x.

semua endpoint merespons dalam < 2 detik.

Jika gagal: kalau hanya satu yang gagal, isolated issue — kemungkinan host di Ingress salah ketik.

41. Smoke test API gateway

Aksi

curl -Ik https://<API_HOST>/api/v1/authentication/

Expected output

HTTP 200 atau 401 (Unauthorized — wajar karena tanpa token).

status code 200 atau 401, bukan 404 atau 502.

Jika gagal: kalau 502 Bad Gateway, kemungkinan onprem-proxy belum Ready — tunggu dan ulang.

42. Smoke test WebSocket notification

Aksi

curl -Ik -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: $(openssl rand -base64 16)" \
  https://<API_HOST>/ws/

Expected output

HTTP 101 Switching Protocols, atau 401 (kalau auth required).

status code 101 atau 401, bukan 404.

Perhatian: WebSocket di-route ke onprem-notification:3008. Kalau 404, periksa annotation Ingress nginx.ingress.kubernetes.io/proxy-read-timeout dan path /ws/.

I. Akses Pertama Kali

Langkah 43–47 melakukan first-login dan setup tenant pertama. Tahap ini memvalidasi bahwa stack sudah usable, bukan hanya healthy.

Credential admin default berikut harus diganti segera setelah first-login. Jangan biarkan credential default aktif di production.

43. Buka URL App FE di browser

Aksi

Buka https://<APP_FE_HOST>/ di browser modern (Chrome/Firefox/Edge terkini).

Expected output

Halaman login AlurKerja dengan logo dan form email/password.

halaman ter-render lengkap (logo + form + tombol login) tanpa error di browser console.

Jika gagal: kalau ada CORS error di console, cek APP_BASE_URL dan API_BASE_URL di ConfigMap (Step 13) — harus konsisten dengan host yang dipakai browser.

44. Login sebagai admin default

Aksi

Masukkan credential default (akan disediakan terpisah oleh tim AlurKerja saat handover) dan klik Login.

Expected output

Redirect ke halaman dashboard atau tenant selection.

URL berubah ke /dashboard atau /tenants.

Jika gagal: kalau gagal login, cek log onprem-auth: kubectl -n ${NAMESPACE} logs deploy/onprem-auth --tail=50.

45. Buat tenant pertama

Aksi

Klik Create Tenant → isi nama tenant + identifier → submit.

Expected output

Tenant baru muncul di list, status Active.

halaman menampilkan banner sukses + tenant baru di list.

Perhatian: identifier tenant biasanya jadi prefix subdomain atau path — koordinasi dengan tim network kalau pakai sub-domain per tenant.

46. Buat user pertama dengan role Owner

Aksi

Di tenant baru, masuk ke menu UsersInvite User → isi email + role Owner → kirim invitation.

Expected output

Email invitation terkirim ke alamat yang di-input; user muncul di list dengan status Pending.

notifikasi sukses + entry baru di tabel Users.

Jika gagal: kalau email tidak terkirim, cek konfigurasi SMTP di alurkerja-config (Step 13). Bisa juga lakukan invite tanpa email dan share link manual.

47. Login sebagai user baru

Aksi

Buka link invitation, set password, login.

Expected output

Redirect ke dashboard tenant; menu navigasi sesuai role Owner.

user baru bisa akses semua menu (Studio, App, Reports, dst).

Perhatian: logout admin default dan jangan dipakai lagi. Set admin default ke disabled setelah Owner pertama terbentuk.

J. Troubleshooting

Tiga skenario error paling umum saat instalasi. Lihat juga Handbook Troubleshooting untuk daftar lebih luas.

Skenario 1: Ingress unreachable (curl connect refused / timeout)

Gejala

  • curl https://<APP_FE_HOST>/ timeout atau "connection refused".
  • Browser menampilkan "site can't be reached".

Aksi diagnostik

kubectl -n ${NAMESPACE} get ingress -o wide
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=50
dig +short <APP_FE_HOST>

Aksi remediasi

  1. Cek ADDRESS Ingress sudah terisi — kalau kosong, tunggu 1–2 menit.
  2. Cek DNS <APP_FE_HOST> mengarah ke EXTERNAL-IP Ingress Controller.
  3. Cek firewall pelanggan (port 80/443 reachable dari client).

Skenario 2: Database connection refused (onprem-* pod CrashLoopBackOff)

Gejala

  • Pod backend stuck CrashLoopBackOff.
  • Log pod menampilkan dial tcp <DB_HOST>:5432: connect: connection refused.

Aksi diagnostik

kubectl -n ${NAMESPACE} logs <POD> --tail=100
kubectl -n ${NAMESPACE} run dbcheck --rm -it --image=postgres:15 -- \
  psql "postgresql://<DB_USER>:<DB_PASSWORD>@<DB_HOST>:<DB_PORT>/<DB_NAME>" -c "SELECT 1;"

Aksi remediasi

  1. Verifikasi credential di alurkerja-secrets (Step 14) cocok dengan database.
  2. Cek security group / firewall — apakah cluster CIDR di-allow di database.
  3. Cek pg_hba.conf di server PostgreSQL — apakah host cluster di-allow.

Skenario 3: ImagePullBackOff saat rollout

Gejala

  • Pod stuck ImagePullBackOff atau ErrImagePull.
  • Event pod menampilkan Failed to pull image "harbor.merapi.javan.id/...": unauthorized.

Aksi diagnostik

kubectl -n ${NAMESPACE} describe pod <POD> | grep -A3 Events
kubectl -n ${NAMESPACE} get secret harbor-regcred -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d

Aksi remediasi

  1. Verifikasi secret harbor-regcred ada dan menunjuk ke harbor.merapi.javan.id (Step 11).
  2. Verifikasi credential Harbor valid (docker login dari mesin lokal — Step 7).
  3. Hapus + buat ulang secret kalau credential expired.
  4. Pastikan imagePullSecrets: [{name: harbor-regcred}] ada di spec Deployment — biasanya sudah di-set di kustomize.

K. Logbook Instalasi

Template berikut sinkron 1:1 dengan nomor langkah di halaman ini. Download versi spreadsheet di alurkerja-install-k8s-checklist.xlsx untuk isi sambil eksekusi.

NoSectionAksiHasilBuktiPICCatatan
1PrasyaratVerifikasi kubectl
2PrasyaratVerifikasi context
3PrasyaratVerifikasi permission
4PrasyaratVerifikasi Ingress Controller
5PrasyaratVerifikasi PostgreSQL
6PrasyaratVerifikasi DNS
7PrasyaratVerifikasi Harbor login
8PersiapanSet variabel
9PersiapanBuat namespace
10PersiapanBuat harbor-regcred
11PersiapanValidasi secret registry
12PersiapanClone repo manifest
13ConfigMapEdit alurkerja-config
14ConfigMapEdit alurkerja-secrets
15ConfigMapEdit camunda-config
16ConfigMapSesuaikan host Ingress
17ConfigMapValidasi key alurkerja-config
18ConfigMapValidasi key alurkerja-secrets
19ConfigMapValidasi key camunda-config
20ConfigMapRender manifest awal
21ConfigMapValidasi tidak ada placeholder
22ConfigMapVerifikasi tidak commit secret
23CamundaInit schema dasar
24CamundaInit schema Camunda
25CamundaValidasi table Camunda
26ApplyRender manifest final
27ApplyValidasi resource kinds
28ApplyValidasi namespace
29Applykubectl apply -k
30ApplyValidasi ConfigMap+Secret
31ApplyValidasi Deployment+Service
32ApplyValidasi Ingress
33VerifikasiRollout Redis
34VerifikasiRollout backend Go
35VerifikasiRollout Camunda
36VerifikasiRollout frontend
37VerifikasiSemua pod Ready
38VerifikasiCamunda readiness
39VerifikasiSmoke test App FE
40VerifikasiSmoke test Studio/Compro/Sim FE
41VerifikasiSmoke test API
42VerifikasiSmoke test WebSocket
43AksesBuka URL App FE
44AksesLogin admin default
45AksesBuat tenant pertama
46AksesBuat user Owner
47AksesLogin user baru

L. Validasi & Sign-off

Setelah seluruh 47 langkah selesai, isi sign-off berikut sebagai bukti instalasi diterima oleh pelanggan.

L.1 Acceptance criteria

ACItemStatusEvidence (cell logbook)
AC 1.1Judul dokumen jelas dan sesuai scope(Section A)
AC 1.2Prasyarat terdokumentasi(Step 1–7)
AC 1.3Langkah instalasi berurutan(Step 1–47)
AC 1.4Konfigurasi awal jelas(Step 13–22)
AC 1.5Verifikasi service tertulis(Step 33–42)
AC 1.6Akses pertama kali terdokumentasi(Step 43–47)
AC 2Troubleshooting tersedia(Section J)

L.2 Sign-off

PeranNamaOrganisasiTanggalStatusCatatan
ImplementorJavan
Reviewer teknisPelanggan
Approver operasionalPelanggan

Status sign-off:

  • Accepted — instalasi diterima tanpa catatan blocker.
  • Accepted with notes — diterima dengan catatan minor (tracked di logbook).
  • Need revision — perlu perbaikan sebelum diterima.

Halaman ini berbasis runbook Linknet (PoC LPP 2025) yang telah teruji di production, di-generalize sebagai dokumentasi onboarding untuk pelanggan AlurKerja berikutnya. Perubahan signifikan: nomor langkah 1..N kontinu lintas section, catatan verifikasi observable per langkah, template logbook dapat di-download. Sumber asli: LINKNET_INSTALLATION_GUIDE.md internal repo alurkerja-link-net-pro.

On this page

A. Ringkasan & Definition of DoneB. Prasyarat1. Verifikasi kubectl terpasang2. Verifikasi context cluster aktif3. Verifikasi permission namespace4. Verifikasi Ingress Controller tersedia5. Verifikasi konektivitas PostgreSQL6. Verifikasi DNS mengarah ke Ingress7. Verifikasi akses Harbor registryC. Arsitektur RingkasD. Persiapan Cluster8. Set variabel instalasi9. Buat namespace target10. Buat secret registry Harbor11. Validasi secret registry dapat dipakai12. Verifikasi clone repo manifestE. ConfigMap & Secret13. Edit alurkerja-config14. Edit alurkerja-secrets15. Edit camunda-config16. Sesuaikan host Ingress17. Validasi kelengkapan key alurkerja-config18. Validasi kelengkapan key alurkerja-secrets19. Validasi camunda-config parseable20. Render manifest awal untuk validasi placeholder21. Validasi tidak ada placeholder tersisa22. Verifikasi tidak ada secret value asli yang akan di-commitF. Schema Camunda23. Inisialisasi schema dasar24. Inisialisasi schema Camunda25. Validasi table Camunda tersediaG. Render & Apply Manifest26. Render manifest final27. Validasi resource kinds di hasil render28. Validasi namespace di hasil render29. Apply manifest ke cluster30. Validasi ConfigMap + Secret applied31. Validasi Deployment + Service applied32. Validasi Ingress appliedH. Verifikasi33. Rollout status Redis34. Rollout status backend Go (11 service)35. Rollout status Camunda36. Rollout status frontend (4 service)37. Validasi semua pod Ready38. Validasi Camunda readiness probe39. Smoke test App FE40. Smoke test Studio FE, Compro FE, Simulation FE41. Smoke test API gateway42. Smoke test WebSocket notificationI. Akses Pertama Kali43. Buka URL App FE di browser44. Login sebagai admin default45. Buat tenant pertama46. Buat user pertama dengan role Owner47. Login sebagai user baruJ. TroubleshootingSkenario 1: Ingress unreachable (curl connect refused / timeout)Skenario 2: Database connection refused (onprem-* pod CrashLoopBackOff)Skenario 3: ImagePullBackOff saat rolloutK. Logbook InstalasiL. Validasi & Sign-offL.1 Acceptance criteriaL.2 Sign-off