DEV Community

Valent Steve Asman
Valent Steve Asman

Posted on Edited on

KerjaLab: Simulasi Kerja Multi-Tier dengan Docker Compose di Localhost

Masalah yang Ingin Diselesaikan

Banyak mahasiswa dan fresh graduate bingung membayangkan seperti apa pekerjaan nyata di bidang yang mereka incar. Teori di kelas tidak selalu sama dengan praktik di dunia kerja. Di sisi lain, perusahaan sulit menilai kemampuan hard skill maupun soft skill kandidat hanya dari CV.

KerjaLab adalah aplikasi web simulasi kerja yang menjawab masalah itu. Pengguna memilih bidang (Teknologi, Sains, Bisnis, atau Soft Skill), mengerjakan simulasi dengan batas waktu, lalu mendapat koin untuk kustomisasi profil dan XP untuk menaikkan level skill. Jika gagal, pengguna boleh mencoba lagi tanpa penalti, sehingga KerjaLab menjadi ruang aman untuk mencoba pekerjaan impian sebelum berkomitmen.

Fitur utamanya:

  • Login Google dengan persetujuan (consent) eksplisit sesuai UU No. 27 Tahun 2022 tentang Pelindungan Data Pribadi.
  • 12 simulasi dalam 4 bidang dengan 3 tingkat kesulitan. Semakin sulit, semakin besar hadiahnya.
  • Tantangan harian dengan streak sebagai bonus.
  • Profil yang menampilkan level hard skill dan soft skill, jumlah dan total waktu simulasi, serta link LinkedIn dan GitHub.
  • Hak penghapusan data: pengguna dapat menghapus akun dan seluruh datanya.

Mengapa Proyek Ini

Saya mengarah ke peran Cloud/DevOps Engineer. Aplikasi ini memberi alasan nyata untuk merancang arsitektur multi-tier: frontend, backend, dan database yang masing-masing berjalan di container, lalu dirakit dengan Docker Compose. Fokus penilaiannya ada pada containerization, jadi fitur dibuat secukupnya.

Arsitektur

Arsitektur Aplikasi

Tiga tier berjalan pada satu user-defined network bernama kerjalab-net:

Container Teknologi Port ke localhost
frontend Next.js 3000
backend Node.js (Express) 4000
db PostgreSQL 16 tidak dibuka
adminer (profile tools) Adminer 8080

Alur request: browser mengakses http://localhost:3000, lalu Next.js meneruskan panggilan /api/* ke http://backend:4000. Backend terhubung ke database lewat db:5432. Data disimpan di named volume kerjalab_pgdata. Database tidak dipublikasikan ke localhost, sehingga hanya container di dalam network yang bisa mengaksesnya.

Container dipilih dibanding virtual machine karena berbagi kernel host. Isolasinya memakai namespaces dan pembatasan sumber daya memakai cgroups, sehingga image jauh lebih kecil dan startup hanya hitungan detik, bukan menit seperti VM.

Dockerfile: Multi-Stage Build

Backend memakai dua stage. Stage builder memasang dependency, sedangkan stage runtime hanya membawa hasil yang diperlukan.

FROM node:22.14.0-alpine3.21 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src ./src

FROM node:22.14.0-alpine3.21 AS runtime
ENV NODE_ENV=production PORT=4000
WORKDIR /app
COPY --from=builder --chown=node:node /app ./
USER node
EXPOSE 4000
CMD ["node", "src/index.js"]
Enter fullscreen mode Exit fullscreen mode

Penjelasan singkat:

  • Tag versi spesifik (22.14.0-alpine3.21), bukan latest, agar build dapat diulang dengan hasil yang sama.
  • File dependency disalin lebih dulu sebelum source code. Selama package.json tidak berubah, layer npm ci diambil dari cache sehingga build jauh lebih cepat.
  • Multi-stage membuat image akhir tidak membawa cache npm dan tool build. Hanya node_modules produksi dan src yang ikut terbawa.
  • COPY, bukan ADD. COPY hanya menyalin file. ADD punya fungsi tambahan (ekstraksi tar dan unduh dari URL) yang membuat perilakunya kurang transparan.
  • CMD dalam exec form membuat proses node menjadi PID 1 dan menerima sinyal penghentian langsung dari Docker.
  • .dockerignore mencegah node_modules, .env, dan .git ikut masuk ke konteks build.

Frontend memakai tiga stage (deps, builder, runtime) dengan mode standalone bawaan Next.js, sehingga image runtime hanya berisi server minimal.

Docker Compose

services:
  db:
    image: postgres:16.6-alpine
    volumes:
      - kerjalab_pgdata:/var/lib/postgresql/data
    networks: [kerjalab-net]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      retries: 10

  backend:
    build: ./backend
    environment:
      DB_HOST: db
    depends_on:
      db:
        condition: service_healthy
    networks: [kerjalab-net]

  adminer:
    image: adminer:4.8.1
    profiles: ["tools"]
Enter fullscreen mode Exit fullscreen mode

Poin pentingnya:

  • Backend memakai DB_HOST: db, yaitu nama service, bukan IP atau localhost. DNS internal Docker yang menerjemahkannya.
  • healthcheck pada database dan depends_on dengan condition: service_healthy memastikan backend baru berjalan setelah PostgreSQL benar-benar siap menerima koneksi.
  • Named volume menjaga data tetap ada setelah docker compose down. Hanya docker compose down -v yang ikut menghapus volume.
  • Konfigurasi dibaca dari file .env. Yang masuk repository hanya .env.example berisi nilai dummy, sehingga tidak ada secret yang ter-commit.
  • Service adminer berada di profile tools, jadi hanya aktif saat dibutuhkan dengan docker compose --profile tools up -d.

Cara Menjalankan di Localhost

git clone https://github.com/valentntnt/KerjaLab.git
cd KerjaLab
cp .env.example .env
docker compose up -d --build
Enter fullscreen mode Exit fullscreen mode

Buka http://localhost:3000. Untuk mengecek kesehatan service:

docker compose ps
curl -i http://localhost:4000/health
Enter fullscreen mode Exit fullscreen mode

Uji docker compose ps

Untuk menguji persistensi, buat data lalu jalankan docker compose down dan docker compose up -d. Data masih ada karena tersimpan di named volume.

Tampilan Aplikasi

Pelajaran yang Didapat

  1. Urutan perintah Dockerfile memengaruhi kecepatan build. Menaruh instruksi yang jarang berubah di atas membuat layer cache terpakai maksimal.
  2. Multi-stage build adalah cara paling sederhana menjaga image tetap ramping tanpa mengorbankan kemudahan proses build.
  3. depends_on saja tidak cukup. Container yang sudah start belum tentu siap. Healthcheck dengan service_healthy menyelesaikan masalah itu.
  4. Pemisahan konfigurasi dari kode lewat .env dan .env.example menjaga secret tetap aman sekaligus memudahkan orang lain menjalankan proyek.
  5. Container memudahkan perpindahan ke cloud. Karena aplikasi sudah dikemas bersama dependensinya, memindahkannya ke VM cloud kelak cukup dengan menginstal Docker lalu menjalankan docker compose up.

Tautan

Top comments (0)