Cara Membuat Docker Image dan Menjalankan Aplikasi Next.js di Docker

Halo teman-teman developer! Pernah nggak sih kalian ngalamin situasi di mana aplikasi Next.js yang udah kalian develop dengan susah payah di laptop pribadi, eh pas di-deploy ke server atau dikasih ke tim lain malah error? "Tapi di laptop gue jalan kok!" - kalimat klasik yang pasti familiar banget di telinga kita semua.

Nah, masalah seperti ini sebenarnya bisa diatasi dengan mudah menggunakan Docker. Bayangin aja Docker ini seperti sebuah "kotak ajaib" yang bisa membungkus aplikasi kita beserta semua dependensinya, mulai dari runtime Node.js, environment variables, sampai konfigurasi sistem operasi sekalipun. Jadi, aplikasi yang jalan di laptop kamu bakal jalan persis sama di server production atau di laptop teman kerja kamu.

Docker menggunakan konsep containerization yang memungkinkan kita untuk "membungkus" aplikasi dalam sebuah container yang isolated dan portable. Berbeda dengan virtual machine yang berat dan memakan resource banyak, Docker container lebih ringan karena berbagi kernel dengan host operating system. Makanya, Docker jadi pilihan favorit developer modern untuk deployment dan development environment.

Untuk aplikasi Next.js, Docker memberikan beberapa keuntungan yang cukup signifikan. Pertama, kita bisa memastikan bahwa versi Node.js dan npm/yarn yang digunakan konsisten di semua environment. Kedua, proses deployment jadi lebih predictable karena semua dependency sudah ter-bundle dalam image. Ketiga, scaling aplikasi jadi lebih mudah karena kita tinggal menjalankan container baru tanpa perlu setup environment dari nol.

Di artikel ini, kita bakal belajar step-by-step cara membuat Docker image untuk aplikasi Next.js, mulai dari setup Dockerfile yang optimal, konfigurasi environment, sampai best practices yang biasa digunakan di production. Kita juga bakal bahas beberapa teknik optimasi seperti multi-stage build dan caching strategies yang bisa bikin build time lebih cepat dan image size lebih kecil.

So, siap-siap ya buat journey kita kali ini. Pastikan kamu udah install Docker di laptop dan punya basic understanding tentang Next.js. Let's containerize your Next.js app!


Persiapan Environment

Nah, sekarang kita masuk ke bagian yang lebih seru nih, yaitu persiapan environment buat dockerize aplikasi Next.js kita. Bagian ini adalah foundation yang super penting, karena kalo setup-nya salah dari awal, nanti bakal ribet troubleshooting-nya. Jadi pastikan kalian ikutin setiap step dengan teliti ya!

Gue tau kadang bagian setup ini membosankan dan pengen langsung loncat ke coding, tapi percayalah, invest waktu di awal buat proper setup bakal save banyak waktu kalian nanti. Plus, once setup ini selesai, kalian bisa pake environment yang sama buat multiple projects ke depannya.

Instalasi Docker

Halaman website docker
Halaman website docker

Langkah pertama yang harus kita lakuin adalah install Docker di komputer kita. Docker itu basically engine yang bakal menjalankan containers kita nanti. Tanpa Docker, semua tutorial ini gak bakal bisa jalan, jadi ini step yang wajib banget.

Download dan install Docker Desktop

Buat kalian yang pake Windows, gue udah siapin tutorial lengkap yang step-by-step banget di BuildWithAngga. Kalian bisa langsung cek di link ini: https://buildwithangga.com/tips/cara-install-docker-desktop-di-windows-tutorial-step-by-step-2025

Tutorial itu comprehensive banget dan udah cover semua edge cases yang mungkin kalian encounter selama proses instalasi. Dari requirement system, troubleshooting WSL2, sampai configuration yang optimal buat development. Seriously, ikutin tutorial itu dulu sebelum lanjut ke step selanjutnya.

Buat yang pake macOS, prosesnya lebih straightforward. Kalian tinggal download Docker Desktop dari official website Docker, terus drag and drop ke Applications folder. Run aplikasinya, dan Docker daemon bakal start automatically. Make sure kalian grant necessary permissions kalo ada popup yang minta authorization.

Untuk Linux users, kalian ada beberapa options. Bisa install Docker Desktop (yang GUI-based kayak Windows dan macOS), atau install Docker Engine aja kalo prefer command line interface. Tapi buat tutorial ini, gue recommend pake Docker Desktop karena lebih user-friendly, especially buat yang baru pertama kali pake Docker.

One important thing yang perlu diperhatiin adalah system requirements. Docker Desktop butuh virtualization support yang enabled di BIOS. Kalo komputer kalian agak lama, pastikan virtualization feature udah di-enable. Tutorial BuildWithAngga yang gue mention tadi juga cover hal ini kok.

Verifikasi instalasi dengan docker --version

Setelah instalasi selesai, step selanjutnya adalah verify bahwa Docker udah properly installed dan running. Cara paling gampang adalah buka terminal atau command prompt, terus jalanin command berikut:

docker --version

Kalo instalasi sukses, kalian bakal see output kayak gini:

Versi Docker
Versi Docker

Version number-nya mungkin beda tergantung kapan kalian install, tapi yang penting adalah command ini running without error. Kalo ada error message, berarti ada something wrong dengan instalasi, dan kalian perlu troubleshoot dulu sebelum lanjut.

Selain check version, gue juga recommend jalanin command ini buat mastiin Docker daemon running properly:

docker info
Docker Info
Docker Info

Command ini bakal show detailed information tentang Docker installation kalian, termasuk storage driver, logging driver, dan various configuration settings. Kalo command ini berhasil run dan show banyak information, berarti Docker udah ready digunakan.

Sebagai final test, coba jalanin hello-world container:

docker run hello-world
Docker run hello-world
Docker run hello-world

Command ini bakal download dan run simple test container. Kalo sukses, kalian bakal see welcome message yang confirm bahwa Docker working correctly. Container ini juga bakal automatic clean up setelah selesai, jadi gak perlu worry tentang cleanup.

Setup project Next.js

Sekarang Docker udah ready, kita perlu setup Next.js project yang bakal kita dockerize. Ada dua scenario di sini: kalian bisa create project baru dari scratch, atau pake existing project yang udah ada. Gue bakal cover both scenarios biar kalian bisa choose yang sesuai dengan situasi kalian.

Membuat project baru atau menggunakan existing project

Kalo kalian mau create project baru, cara paling gampang adalah pake create-next-app. Ini adalah official tool dari Next.js buat scaffolding new projects dengan best practices dan optimal configuration. Jalanin command berikut di terminal:

npx create-next-app@latest buildwithangga-docker-app

Setelah jalanin command ini, kalian bakal ditanya beberapa configuration options. Buat tutorial ini, gue recommend pilih options berikut:

  • TypeScript: Yes (tapi kalo kalian prefer JavaScript, gak masalah juga)
  • ESLint: Yes
  • Tailwind CSS: Yes (optional, tapi recommended)
  • App Router: Yes (ini adalah new routing system di Next.js 13+)
  • Turbopack: Yes
  • Import alias: Yes
Setup Proyek Next.js
Setup Proyek Next.js

Proses ini bakal take beberapa menit karena npm install semua dependencies. Once selesai, kalian bakal punya project structure yang clean dan ready buat development.

Kalo kalian udah punya existing Next.js project, pastikan project tersebut running properly di local environment dulu sebelum di-dockerize. Jalanin npm run dev atau yarn dev dan make sure aplikasi accessible di browser tanpa error. Ini penting karena kalo ada issue di aplikasi itu sendiri, nanti bisa confusing apakah masalahnya dari aplikasi atau dari Docker setup.

Buat existing projects, juga pastikan dependencies udah up-to-date dan compatible dengan latest Docker practices. Some older Next.js versions mungkin punya quirks tertentu yang perlu additional configuration di Docker.

Struktur folder yang akan digunakan

Understanding project structure adalah crucial buat effective dockerization. Default Next.js project structure udah quite good buat Docker, tapi ada beberapa hal yang perlu diperhatiin.

Typical Next.js project structure look like this:

Struktur proyek
Struktur proyek

Yang important buat diperhatiin adalah folder-folder yang gak perlu di-include dalam Docker image. Folder kayak node_modules, .next, dan .git seharusnya gak di-copy ke Docker image karena bakal bikin image size jadi bloated unnecessarily.

Gue juga recommend create .dockerignore file di root project. File ini similar dengan .gitignore, tapi specifically buat Docker build context. Ini bakal optimize build performance dan reduce image size significantly.

Contents dari .dockerignore file biasanya include:

node_modules
.next
.git
.gitignore
README.md
Dockerfile
.dockerignore
npm-debug.log*
yarn-debug.log*
yarn-error.log*

Buat project yang lebih complex, mungkin kalian juga punya additional folders kayak docs, tests, atau scripts yang gak perlu di-include dalam production Docker image. Customize .dockerignore file sesuai dengan needs project kalian.

Dependencies yang diperlukan

Sebelum kita create Dockerfile, pastikan semua dependencies udah properly configured. This includes runtime dependencies, development dependencies, dan build tools yang necessary buat compile dan run Next.js application.

Node.js dan npm/yarn

Halaman website Nodjs
Halaman website Nodjs

Next.js adalah Node.js-based framework, jadi obviously kita butuh Node.js runtime. Tapi yang tricky adalah choosing the right version. Different Next.js versions punya different Node.js requirements, dan ada compatibility issues yang perlu diperhatiin.

Yang perlu diperhatiin adalah versi Node.js yang tepat. Next.js versi terbaru (Next.js 13 ke atas) butuh minimal Node.js versi 16.14.0, tapi gue saranin pake Node.js 18.17.0 atau yang lebih baru. Versi ini udah include perbaikan performa dan keamanan yang penting buat aplikasi production.

Yang perlu diperhatiin juga adalah pilihan antara npm dan yarn. Keduanya sama-sama bagus kok, tapi pastikan kalian konsisten pake satu aja di sepanjang project. Kalo kalian mulai dengan npm, terus pake npm sampai selesai. Kalo mulai dengan yarn, ya pake yarn terus. Kenapa? Karena kalo campur-campur package manager bisa bikin masalah dependency yang ribet buat di-debug nanti.

Buat check Node.js version di local machine kalian:

node --version

Dan buat check npm version:

npm --version
Versi node dan npm
Versi node dan npm

Kalo kalian pake yarn:

yarn --version

Penting banget nih: versi yang kalian pake di komputer lokal gak harus sama dengan versi yang bakal kita pake dalam Docker container. Sebenernya, ini salah satu keuntungan Docker - kita bisa tentuin versi yang tepat yang mau kita pake, terlepas dari setup di komputer lokal kalian.

Package.json configuration

File package.json adalah jantungnya project Node.js. File ini berisi informasi tentang project, daftar dependency yang dibutuhkan, dan script-script yang bisa dijalankan. Buat setup Docker, ada beberapa konfigurasi yang sangat penting.

Pertama, pastikan bagian scripts berisi command-command yang diperlukan. Script minimal yang dibutuhkan adalah:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }
}

Script dev buat jalanin development server, build buat create production build, start buat jalanin production server, dan lint buat cek kualitas kode. Dalam konteks Docker, yang paling penting adalah script build dan start.

Bagian dependencies juga perlu diperhatiin dengan baik. Pastikan semua dependency yang diperlukan buat jalanin aplikasi masuk ke dalam dependencies, bukan devDependencies. DevDependencies itu cuma diperlukan waktu development dan build process, tapi gak dibutuhkan saat aplikasi jalan di production.

Contoh konfigurasi dependencies yang benar:

{
  "dependencies": {
    "next": "14.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "@types/react": "^18.2.0",
    "@types/react-dom": "^18.2.0",
    "eslint": "^8.45.0",
    "eslint-config-next": "14.0.0",
    "typescript": "^5.0.0"
  }
}

Yang juga penting adalah field engines. Field ini menentukan persyaratan versi Node.js buat project kita. Ini berguna buat memastikan kompatibilitas dan menghindari masalah runtime:

{
  "engines": {
    "node": ">=18.17.0",
    "npm": ">=9.0.0"
  }
}

Beberapa konfigurasi tambahan yang mungkin berguna buat setup Docker:

{
  "config": {
    "port": "3000"
  }
}

Konfigurasi port ini bisa di-reference dalam script atau environment setup, jadi lebih gampang buat customize pengaturan deployment.

Juga pertimbangkan buat nambahin konfigurasi browserslist kalo kalian targeting browser tertentu. Ini mempengaruhi output build dan bisa optimize ukuran bundle:

{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

Terakhir tapi gak kalah penting, pastikan package-lock.json (kalo pake npm) atau yarn.lock (kalo pake yarn) di-commit ke repository. Lock files ini memastikan versi dependency yang konsisten di berbagai environment, yang sangat penting buat reproducible builds dalam Docker.

Setelah semua setup ini selesai, jalanin npm install atau yarn install buat mastiin semua dependency terinstall dengan benar dan gak ada konflik. Juga jalanin npm run build sekali buat verify bahwa build process jalan dengan lancar.

Setelah semua langkah di section ini selesai, environment kalian udah siap buat mulai bikin Dockerfile dan dockerizing aplikasi Next.js. Section selanjutnya kita bakal deep dive ke anatomi Dockerfile dan memahami setiap komponen yang diperlukan buat containerization yang sukses.

Halaman Proyek Next.js
Halaman Proyek Next.js

Memahami Dockerfile untuk Next.js

Nah, sekarang kita masuk ke bagian yang paling seru nih - bikin Dockerfile! Ini adalah bagian inti dari seluruh proses dockerization. Kalo sebelumnya kita cuma persiapan environment, sekarang kita bakal hands-on bikin blueprint buat container kita. Anggap aja Dockerfile ini kayak resep masakan - kita kasih tau Docker step by step apa aja yang harus dilakuin buat bikin container yang sempurna.

Gue tau mungkin konsep Dockerfile ini keliatan rumit di awal, tapi tenang aja. Kita bakal bahas dari dasar-dasarnya dulu, terus nanti kita praktek langsung bikin Dockerfile buat aplikasi BuildWithAngga kita. Setelah kalian paham konsepnya, percayalah bakal jadi lebih gampang dan bahkan addictive buat optimize terus.

Konsep dasar Dockerfile

Sebelum kita mulai nulis kode, kita perlu paham dulu apa sebenernya Dockerfile itu dan gimana cara kerjanya. Pemahaman yang solid tentang fundamental ini bakal bikin kalian lebih confident pas praktek nanti.

Apa itu Dockerfile dan bagaimana cara kerjanya

Cara Kerja Dockerfile
Cara Kerja Dockerfile

Dockerfile itu sebenernya cuma file teks biasa yang berisi serangkaian instruksi atau perintah. File ini kayak cetak biru yang kasih tau Docker gimana cara bikin image. Bayangkan kayak kalian lagi kasih petunjuk ke teman buat bikin kue - kalian kasih tau langkah demi langkah, mulai dari bahan apa aja yang dibutuhin, gimana cara nyampurnya, berapa lama dioven, dan seterusnya.

Yang menarik dari Dockerfile adalah dia pake konsep layer. Setiap instruksi dalam Dockerfile bakal jadi satu lapisan dalam image. Lapisan-lapisan ini ditumpuk satu per satu, kayak susun kue lapis. Keuntungannya adalah kalo ada perubahan di satu lapisan, Docker cuma perlu rebuild lapisan itu aja sama lapisan-lapisan setelahnya. Lapisan yang udah gak berubah bakal di-simpan sementara, jadi proses build jadi lebih cepet.

Misalnya kalian punya Dockerfile dengan 10 instruksi. Kalo kalian cuma ubah instruksi ke-8, Docker gak perlu rebuild dari awal. Dia bakal pake data yang tersimpan sampe instruksi ke-7, terus mulai rebuild dari instruksi ke-8. Ini adalah salah satu fitur powerful dari Docker yang bikin alur kerja development jadi efisien.

Dockerfile juga harus ada di folder utama project kalian, dan nama filenya harus persis "Dockerfile" (tanpa extension apapun). Docker bakal otomatis nyari file ini pas kalian jalanin perintah build. Kalian juga bisa kasih nama lain sih, tapi harus sebutin nama filenya pas build.

Cara kerja Dockerfile itu berurutan - instruksi dijalanin dari atas ke bawah, satu per satu. Jadi urutan instruksi itu penting banget. Kalo salah satu instruksi gagal, proses build bakal berhenti dan kasih pesan error. Makanya penting buat ngetest setiap perubahan dan pastikan penulisan kodenya benar.

Struktur Dockerfile untuk Next.js

Sekarang kita udah paham instruksi-instruksi dasar, kita bahas gimana cara nyusun Dockerfile yang optimal buat aplikasi Next.js. Ada beberapa hal yang perlu dipertimbangkan, mulai dari pemilihan image dasar sampe strategi build yang efisien.

Pemilihan image dasar (node:alpine vs node:slim)

Pemilihan image dasar itu crucial banget buat performa dan keamanan container. Ada beberapa varian Node.js image yang tersedia, dan masing-masing punya kelebihan dan kekurangan. Yang paling populer buat production adalah node:alpine dan node:slim.

node:alpine adalah pilihan yang paling populer karena ukurannya yang sangat kecil. Alpine Linux itu distro Linux yang minimal banget, cuma berisi komponen-komponen penting aja. Image node:alpine ukurannya cuma sekitar 40-50 MB, jauh lebih kecil dibanding varian lain. Ini bikin download image jadi cepet, push/pull dari registry jadi efisien, dan kebutuhan storage jadi minimal.

Tapi ada trade-off nya juga. Alpine pake musl libc instead of glibc yang dipake kebanyakan distribusi Linux. Kadang ada masalah kompatibilitas dengan beberapa native modules atau dependencies yang expect glibc. Tapi buat kebanyakan aplikasi Next.js, ini gak jadi masalah.

Contoh penggunaan:

FROM node:24-alpine

node:slim adalah compromise antara ukuran dan compatibility. Image ini based on Debian, tapi udah di-strip dari packages yang gak necessary. Ukurannya lebih besar dari Alpine (sekitar 70-80 MB), tapi masih jauh lebih kecil dari full Debian image. Kompatibilitasnya lebih baik karena pake glibc.

Contoh penggunaan:

FROM node:24-slim

Buat aplikasi BuildWithAngga yang kompleks dengan banyak dependencies, gue recommend mulai dengan node:alpine. Kalo nanti ada masalah kompatibilitas, baru switch ke node:slim. Kebanyakan waktu, Alpine works perfectly fine.

Ada juga varian lain kayak node:buster atau node:bullseye yang berbasis full Debian, tapi ukurannya jauh lebih besar (300+ MB). Kecuali kalian butuh tools atau libraries khusus yang cuma ada di OS lengkap, hindari varian-varian ini.

Konsep multi-stage build

Multi-stage build adalah teknik lanjutan yang bisa dramatically reduce ukuran final image. Konsepnya adalah kita pake multiple FROM statements dalam satu Dockerfile, dimana setiap tahap punya tujuan yang beda. Tahap pertama biasanya buat build aplikasi (termasuk install dev dependencies), tahap kedua buat production runtime (cuma runtime dependencies).

Kenapa ini penting? Karena proses build Next.js butuh banyak dev dependencies kayak TypeScript compiler, ESLint, testing frameworks, dll. Tapi buat jalanin aplikasi di production, kita cuma butuh production dependencies dan built artifacts. Multi-stage build memungkinkan kita build aplikasi dengan semua tools yang dibutuhin, tapi final image cuma berisi apa yang diperlukan buat runtime.

Struktur basic multi-stage build:

# Stage 1: Build stage
FROM node:24-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Production stage
FROM node:24-alpine AS runner
WORKDIR /app
COPY package*.json ./
RUN npm install --only=production
COPY --from=builder /app/.next ./.next
CMD ["npm", "start"]

Stage pertama (builder) install semua dependencies termasuk devDependencies, copy source code, dan build aplikasi. Stage kedua (runner) cuma install production dependencies dan copy built artifacts dari stage pertama. Final image cuma contain stage terakhir, jadi ukurannya jauh lebih kecil.

Benefits dari multi-stage build:

  • Ukuran image yang jauh lebih kecil
  • Security yang lebih baik (gak ada dev tools di production)
  • Clear separation between build dan runtime environment
  • Faster deployment karena image size kecil

Contoh Dockerfile sederhana

Sekarang kita praktek bikin Dockerfile sederhana buat aplikasi BuildWithAngga. Gue bakal jelasin step by step setiap baris dan kasih komentar yang jelas buat memudahkan pemahaman.

Step-by-step explanation setiap baris

Mari kita mulai dengan Dockerfile yang simple tapi functional:

# Gunakan Node.js 24 dengan Alpine Linux sebagai base image
FROM node:24-alpine

# Set working directory di dalam container
WORKDIR /app

# Copy package.json dan package-lock.json (jika ada)
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy seluruh source code ke dalam container
COPY . .

# Build aplikasi Next.js untuk production
RUN npm run build

# Expose port 3000 (port default Next.js)
EXPOSE 3000

# Set environment variable untuk production
ENV NODE_ENV=production

# Jalankan aplikasi
CMD ["npm", "start"]

Komentar untuk memudahkan pemahaman

Sekarang gue jelasin detil setiap bagian dari Dockerfile di atas:

Baris 1-2: Base Image Selection

# Gunakan Node.js 18 dengan Alpine Linux sebagai base image
FROM node:24-alpine

Kita mulai dengan node:24-alpine sebagai base image. Ini kasih kita Node.js runtime versi 18 di atas Alpine Linux yang lightweight. Alpine dipilih karena ukurannya kecil tapi tetep reliable buat production. Versi 18 adalah LTS version yang stable dan compatible dengan Next.js versi terbaru.

Baris 3-5: Working Directory Setup

# Set working directory di dalam container
WORKDIR /app

WORKDIR create dan set /app sebagai working directory. Semua command selanjutnya bakal dijalanin di directory ini. Ini good practice buat organize files dalam container dan avoid conflicts dengan system directories.

Baris 6-8: Package Files Copy

# Copy package.json dan package-lock.json (jika ada)
COPY package*.json ./

Kita copy package.json dan package-lock.json dulu sebelum copy source code. Ini adalah optimization technique buat leverage Docker layer caching. Karena package files jarang berubah dibanding source code, layer ini bakal di-cache dan gak perlu rebuild kalo cuma ada perubahan kode.

Baris 9-11: Dependencies Installation

# Install dependencies
RUN npm install

Install semua dependencies yang listed dalam package.json. Karena kita belum set NODE_ENV ke production, npm bakal install semua dependencies termasuk devDependencies. Ini perlu buat build process.

Baris 12-14: Source Code Copy

# Copy seluruh source code ke dalam container
COPY . .

Copy semua files dari build context (folder tempat Dockerfile berada) ke working directory dalam container. File .dockerignore bakal exclude files yang gak perlu, kayak node_modules, .git, dll.

Baris 15-17: Application Build

# Build aplikasi Next.js untuk production
RUN npm run build

Jalanin build process Next.js yang generate optimized production bundle. Command ini bakal create .next folder yang berisi compiled application, static assets, dan optimized JavaScript bundles.

Baris 18-20: Port Declaration

# Expose port 3000 (port default Next.js)
EXPOSE 3000

Declare bahwa aplikasi bakal listen di port 3000. Ini mostly buat dokumentasi, karena gak automatically publish port ke host. Saat run container, kita tetep harus specify port mapping.

Baris 21-23: Environment Configuration

# Set environment variable untuk production
ENV NODE_ENV=production

Set NODE_ENV ke production. Ini kasih tau Next.js dan dependencies lain bahwa aplikasi running dalam production mode, yang enable various optimizations dan disable development features.

Baris 24-26: Startup Command

# Jalankan aplikasi
CMD ["npm", "start"]

Specify default command yang bakal dijalanin pas container start. npm start bakal jalanin production server Next.js yang serve aplikasi yang udah di-build sebelumnya.

Dockerfile ini simple tapi udah cukup buat run aplikasi BuildWithAngga dalam container. Tapi masih ada beberapa optimization yang bisa kita lakuin, kayak multi-stage build, better caching strategy, dan security improvements. Di section selanjutnya kita bakal explore teknik-teknik advanced buat bikin Dockerfile yang lebih optimal dan production-ready.

Yang penting sekarang adalah kalian udah paham konsep dasar dan bisa bikin Dockerfile sederhana yang working. Practice bikin Dockerfile dengan berbagai aplikasi Next.js buat get familiar dengan syntax dan common patterns.

Cara Menjalankan Dockerfile

Setelah kita udah bikin Dockerfile, langkah selanjutnya adalah build image dan jalanin container. Ini adalah bagian dimana semua teori yang udah kita pelajari jadi praktek nyata. Gue bakal jelasin step by step gimana cara build dan run Dockerfile yang udah kita buat.

Build Docker Image

Langkah pertama adalah build Docker image dari Dockerfile yang udah kita buat. Pastikan kalian ada di direktori yang sama dengan Dockerfile, terus jalanin perintah ini:

docker build -t buildwithangga-nextjs .
Docker images berhasil dibuat
Docker images berhasil dibuat

Mari kita breakdown perintah ini:

  • docker build adalah perintah buat build image dari Dockerfile
  • t buildwithangga-nextjs kasih nama (tag) ke image kita. Kalian bisa ganti nama ini sesuai keinginan
  • . titik di akhir artinya Docker bakal nyari Dockerfile di direktori sekarang

Proses build ini bakal take beberapa menit, tergantung kecepatan internet kalian (buat download base image) dan kompleksitas aplikasi. Kalian bakal lihat output kayak gini:

Sending build context to Docker daemon  2.048kB
Step 1/8 : FROM node:24-alpine
 ---> a1b2c3d4e5f6
Step 2/8 : WORKDIR /app
 ---> Running in 1234567890ab
 ---> 9876543210cd
...
Successfully built a1b2c3d4e5f6
Successfully tagged buildwithangga-nextjs:latest

Setiap step correspond dengan satu instruksi dalam Dockerfile. Kalo ada error, Docker bakal kasih tau di step mana error-nya terjadi.

Docker build success
Docker build success

Run Docker Container

Setelah image berhasil di-build, sekarang kita bisa jalanin container dari image tersebut:

docker run -p 3000:3000 buildwithangga-nextjs

Penjelasan perintah ini:

  • docker run perintah buat jalanin container dari image
  • p 3000:3000 mapping port. Format-nya host_port:container_port. Ini artinya port 3000 di komputer kalian bakal di-forward ke port 3000 di dalam container
  • buildwithangga-nextjs nama image yang mau di-run

Kalo berhasil, kalian bakal lihat output kayak:

Menjalankan Docker Container
Menjalankan Docker Container
Di Docker Desktop juga akan muncul
Di Docker Desktop juga akan muncul

Sekarang buka browser dan akses http://localhost:3000. Kalian harusnya bisa lihat aplikasi Next.js kalian running dalam Docker container!

Menjalankan Next.js di docker
Menjalankan Next.js di docker

Run Container di Background

Kalo kalian mau jalanin container di background (detached mode), tambahin flag -d:

docker run -d -p 3000:3000 --name buildwithangga-app buildwithangga-nextjs

Flag --name kasih nama ke container biar gampang diingat. Sekarang container bakal jalan di background dan kalian bisa continue pake terminal buat hal lain.

image.png
Docker run

Lihat Container yang Running

Buat cek container yang lagi jalan:

docker ps
Docker container
Docker container

Buat lihat semua container (termasuk yang udah stop):

docker ps -a
Semua docker container
Semua docker container

Stop dan Remove Container

Buat stop container:

docker stop buildwithangga-app

Buat remove container:

docker rm buildwithangga-app

Tips Debugging

Kalo ada masalah, kalian bisa lihat logs container:

docker logs buildwithangga-app

Atau masuk ke dalam container buat debugging:

docker exec -it buildwithangga-app /bin/sh

Perintah ini bakal kasih kalian shell access ke dalam container, jadi kalian bisa explore file system dan debug masalah.

Build dengan Cache

Docker punya sistem cache yang intelligent. Kalo kalian rebuild image dan gak ada perubahan di layer tertentu, Docker bakal pake cache. Tapi kalo kalian mau force rebuild tanpa cache:

docker build --no-cache -t buildwithangga-nextjs .

Dengan pemahaman cara build dan run Docker images ini, kalian udah bisa mulai experiment dengan aplikasi Next.js dalam container environment. Next section kita bakal explore teknik-teknik advanced buat optimize Docker workflow dan production deployment.


Membuat Dockerfile yang Dioptimalkan

Nah, sekarang kita masuk ke bagian yang lebih seru nih - bikin Dockerfile yang bener-bener optimal! Di bagian sebelumnya kita udah paham konsep dasar, sekarang saatnya praktek bikin Dockerfile yang gak cuma working, tapi juga efisien dan siap buat produksi. Kalo sebelumnya kita bikin Dockerfile sederhana, sekarang kita bakal explore berbagai teknik optimasi yang bikin image kita lebih kecil, lebih aman, dan lebih cepet.

Gue tau mungkin keliatan overwhelming di awal, tapi percayalah setelah kalian paham prinsip-prinsipnya, kalian bakal ketagihan optimize terus. Plus, skill optimasi Docker ini bakal berguna banget buat karir kalian kedepannya, apalagi di era cloud computing dan microservices kayak sekarang.

Single-stage Dockerfile

Kita mulai dulu dari yang simple - single-stage Dockerfile yang udah dioptimasi. Meskipun namanya "single-stage", bukan berarti kita gak bisa optimize sama sekali. Ada banyak teknik yang bisa kita pake buat bikin Dockerfile yang lebih efisien bahkan dalam satu tahap aja.

Implementasi Dockerfile dasar

Mari kita lihat contoh Dockerfile single-stage yang udah dioptimasi buat aplikasi BuildWithAngga:

# Gunakan Node.js 24 dengan Alpine Linux sebagai image dasar
FROM node:24-alpine

# Install dependencies yang dibutuhkan sistem
RUN apk add --no-cache libc6-compat

# Set working directory
WORKDIR /app

# Copy file package.json dan lock file
COPY package.json package-lock.json* ./

# Install dependencies menggunakan npm install untuk menghindari sync issues
RUN npm install --only=production && npm cache clean --force

# Copy source code
COPY . .

# Build aplikasi Next.js
RUN npm run build

# Buat user non-root untuk keamanan
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Set ownership file ke user nextjs
RUN chown -R nextjs:nodejs /app

# Switch ke user non-root
USER nextjs

# Expose port 3000
EXPOSE 3000

# Set environment variable
ENV NODE_ENV=production
ENV PORT=3000

# Health check untuk monitoring
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
  CMD curl -f <http://localhost:3000/api/health> || exit 1

# Jalanin aplikasi
CMD ["npm", "start"]

Penjelasan setiap instruksi

Sekarang gue jelasin satu per satu kenapa kita pake instruksi-instruksi ini dan apa manfaatnya:

Baris 1-2: Image dasar dan dependency sistem

FROM node:24-alpine
RUN apk add --no-cache libc6-compat

Kita pake node:24-alpine karena ukurannya yang kecil. libc6-compat diinstall karena beberapa dependency Node.js butuh compatibility layer buat jalan di Alpine. Flag --no-cache memastikan package cache gak disimpan, jadi ukuran image tetep kecil.

Baris 3-5: Working directory setup

WORKDIR /app

Set working directory ke /app. Semua operasi selanjutnya bakal dilakuin di directory ini.

Baris 6-8: Copy package files

COPY package.json package-lock.json* ./

Kita copy package.json dan package-lock.json dulu sebelum copy source code. Tanda * setelah package-lock.json artinya file ini optional - kalo ada bakal di-copy, kalo gak ada ya gak apa-apa. Ini penting buat Docker layer caching.

Baris 9-11: Install dependencies

RUN npm ci --only=production && npm cache clean --force

npm ci lebih cepet dan reliable dibanding npm install buat production builds, tapi perlu package-lock.json yang sync. Kalo kalian dapet error tentang package.json dan package-lock.json yang gak sync, kalian punya beberapa pilihan:

Pilihan 1: Update package-lock.json dulu Jalanin di local machine kalian:

npm install

Terus commit package-lock.json yang baru ke repository.

Pilihan 2: Pake npm install instead Ganti npm ci dengan npm install di Dockerfile:

RUN npm install --only=production && npm cache clean --force

Pilihan 3: Generate lock file di dalam container

RUN npm install && npm ci --only=production && npm cache clean --force

Buat tutorial ini, gue recommend pake pilihan 2 yang lebih simple dan less error-prone. Flag --only=production memastikan kita cuma install production dependencies. npm cache clean --force bersihin cache buat reduce ukuran image.

Baris 12-17: Copy source dan build

COPY . .
RUN npm run build

Copy semua source code, terus build aplikasi Next.js. Ini menghasilkan folder .next yang berisi optimized production build.

Baris 18-24: Setup keamanan

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN chown -R nextjs:nodejs /app
USER nextjs

Ini adalah best practice keamanan. Kita bikin user non-root khusus buat jalanin aplikasi. Running aplikasi sebagai root user itu security risk yang gede, jadi kita avoid ini dengan bikin dedicated user.

Baris 25-30: Configuration

EXPOSE 3000
ENV NODE_ENV=production
ENV PORT=3000

Declare port yang dipake dan set environment variables yang diperlukan. NODE_ENV=production ngasih tau Next.js dan dependencies lain bahwa ini production environment.

Baris 31-34: Health check

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
  CMD curl -f <http://localhost:3000/api/health> || exit 1

Health check memungkinkan Docker monitor apakah container masih healthy. Setiap 30 detik Docker bakal cek endpoint /api/health. Kalo endpoint ini gak respond dalam 3 detik atau return error, container dianggap unhealthy.

Keuntungan dan kekurangan

Single-stage Dockerfile punya beberapa keuntungan:

Keuntungan:

  • Simple dan mudah dipahami
  • Build process yang straightforward
  • Debugging yang lebih gampang karena semua ada dalam satu stage
  • Good enough buat most aplikasi yang gak terlalu kompleks

Kekurangan:

  • Ukuran image yang lebih besar karena masih include build tools
  • Less secure karena production container masih contain development tools
  • Gak optimal buat aplikasi dengan build process yang kompleks
  • Cache efficiency yang kurang optimal

Buat aplikasi BuildWithAngga yang simple, single-stage Dockerfile ini udah cukup good. Tapi kalo aplikasi kalian mulai kompleks atau kalian care banget sama image size dan security, multi-stage build adalah pilihan yang lebih baik.

Single Stage Dockerfile
Single Stage Dockerfile

Multi-stage Dockerfile

Multi-stage build adalah teknik yang powerful banget buat optimize Docker images. Dengan teknik ini, kita bisa significantly reduce ukuran final image dan improve security dengan memisahin build environment dari production environment.

Konsep tahap build dan tahap produksi

Konsep dasarnya simple: kita punya dua tahap terpisah dalam satu Dockerfile. Tahap pertama (build stage) berisi semua tools dan dependencies yang dibutuhkan buat build aplikasi. Tahap kedua (production stage) cuma berisi apa yang diperlukan buat jalanin aplikasi.

Analogi yang gampang: bayangin kalian mau bikin kue. Tahap pertama adalah nyiapin semua bahan, mixer, oven, dan tools lainnya buat bikin kue. Tahap kedua adalah cuma ambil kue yang udah jadi dan taro di kotak buat dijual. Customer gak perlu tau proses pembuatannya, mereka cuma mau kue yang udah jadinya aja.

Optimasi ukuran image

Multi-stage build bisa reduce ukuran image sampe 60-80% dalam beberapa kasus. Ini terjadi karena:

  • Build dependencies gak ikut masuk ke final image
  • Development tools kayak TypeScript compiler, ESLint, testing frameworks, dll gak ada di production
  • Source code yang gak tercompile gak ikut masuk
  • npm cache dan temporary files otomatis ke-exclude

Buat aplikasi BuildWithAngga yang kompleks, perbedaan ukuran ini bisa signifikan banget. Image yang tadinya 800MB bisa jadi cuma 200MB.

Contoh implementasi lengkap

Ini contoh multi-stage Dockerfile yang comprehensive buat aplikasi BuildWithAngga:

# ===================
# Build Stage
# ===================
FROM node:24-alpine AS builder

# Install system dependencies untuk build process
RUN apk add --no-cache libc6-compat

# Set working directory
WORKDIR /app

# Copy package files buat caching yang optimal
COPY package.json package-lock.json* ./

# Install SEMUA dependencies (termasuk devDependencies)
RUN npm install && npm cache clean --force

# Copy source code
COPY . .

# Build aplikasi Next.js
RUN npm run build

# ===================
# Production Stage
# ===================
FROM node:24-alpine AS runner

# Install system dependencies minimal
RUN apk add --no-cache \\
    curl \\
    dumb-init

# Set working directory
WORKDIR /app

# Buat user non-root buat keamanan
RUN addgroup --system --gid 1001 nodejs && \\
    adduser --system --uid 1001 nextjs

# Copy package files
COPY package.json package-lock.json* ./

# Install CUMA production dependencies
RUN npm install --only=production && \\
    npm cache clean --force

# Copy built application dari build stage
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public

# Copy additional files yang dibutuhkan (jika ada)
# Cek dulu apakah file ini ada di project kalian
COPY --from=builder /app/next.config.js* ./

# Set ownership ke nextjs user
RUN chown -R nextjs:nodejs /app

# Switch ke user non-root
USER nextjs

# Expose port
EXPOSE 3000

# Set environment variables
ENV NODE_ENV=production
ENV PORT=3000
ENV NEXT_TELEMETRY_DISABLED=1

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
  CMD curl -f <http://localhost:3000/api/health> || exit 1

# Use dumb-init buat proper signal handling
ENTRYPOINT ["/usr/bin/dumb-init", "--"]

# Jalanin aplikasi
CMD ["npm", "start"]

Yang menarik dari implementasi ini adalah kita pake COPY --from=builder buat ambil hasil build dari stage sebelumnya. Ini memungkinkan kita copy cuma file-file yang diperlukan buat production.

Perhatiin juga bahwa di production stage, kita cuma install production dependencies dengan --only=production. Ini significantly reduce ukuran node_modules dan improve startup time.

Important Note: Kalo project kalian gak punya file next.config.js, kalian bisa skip baris copy tersebut atau pake wildcard pattern next.config.* supaya gak error kalo file gak ada.

Multi Stage Dockerfile
Multi Stage Dockerfile

Environment variables dan konfigurasi

Environment variables adalah cara yang flexible buat konfigurasi aplikasi Docker. Dengan proper environment variable setup, kalian bisa pake image yang sama buat berbagai environment (development, staging, production) dengan konfigurasi yang beda-beda.

Setting NODE_ENV

NODE_ENV adalah environment variable yang paling penting buat aplikasi Node.js. Variable ini nentuin mode aplikasi berjalan dan mempengaruhi banyak behavior:

ENV NODE_ENV=production

Pas NODE_ENV di-set ke "production":

  • Next.js enable various optimizations
  • Dependencies kayak React jalan dalam production mode
  • Error messages jadi less verbose (lebih aman)
  • Caching behavior jadi more aggressive
  • Source maps biasanya disabled

Kalo kalian mau bikin image yang bisa dipake buat multiple environments, kalian bisa set default value tapi allow override:

ENV NODE_ENV=production

Terus pas run container, kalian bisa override:

docker run -e NODE_ENV=development buildwithangga-app

Konfigurasi port

Port configuration juga important buat flexibility. Instead of hardcode port dalam aplikasi, better practice adalah pake environment variable:

ENV PORT=3000

Nah, buat Next.js, kalian gak perlu nulis kode manual buat listen ke port karena Next.js udah handle ini secara otomatis. Next.js bakal otomatis baca environment variable PORT dan listen ke port tersebut.

Tapi kalo kalian pake custom server (misalnya Express.js dengan Next.js), baru kalian perlu nulis kode kayak gini di file server.js atau app.js:

// server.js (kalo pake custom server)
const express = require('express');
const next = require('next');

const port = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });

app.prepare().then(() => {
  const server = express();

  server.listen(port, () => {
    console.log(`BuildWithAngga app running on port ${port}`);
  });
});

Tapi buat most cases dengan Next.js standar, kalian cukup pake script yang udah ada di package.json:

{
  "scripts": {
    "start": "next start -p $PORT"
  }
}

Atau kalo mau lebih simple lagi, Next.js bakal otomatis detect PORT environment variable tanpa perlu specify apapun. Jadi cukup:

{
  "scripts": {
    "start": "next start"
  }
}

Ini memungkinkan kalian jalanin multiple containers di port yang beda-beda tanpa perlu rebuild image:

# Container pertama di port 3000
docker run -p 3000:3000 buildwithangga-app

# Container kedua di port 3001
docker run -p 3001:3000 -e PORT=3000 buildwithangga-app

Custom environment variables

Buat aplikasi BuildWithAngga yang real-world, kalian pasti butuh environment variables tambahan. Gue kasih contoh yang simple dan mudah dipahami:

# Konfigurasi aplikasi dasar
ENV APP_NAME="BuildWithAngga Course Platform"
ENV APP_VERSION="1.0.0"

# URL aplikasi (berguna buat email notifications, dll)
ENV BASE_URL="<https://buildwithangga.com>"

# Fitur-fitur yang bisa di on/off
ENV SHOW_PROMO_BANNER=true
ENV ENABLE_DARK_MODE=true
ENV MAINTENANCE_MODE=false

# Konfigurasi email (kosongkan buat diisi saat running)
ENV SMTP_HOST=""
ENV SMTP_PORT=587
ENV FROM_EMAIL="[email protected]"

Kenapa kita pake environment variables? Karena dengan cara ini, kita bisa:

  • Pake image yang sama buat berbagai lingkungan (development, production)
  • Gampang ubah konfigurasi tanpa rebuild image
  • Sembunyiin data sensitif kayak password

Contoh cara ngisi environment variables pas jalanin container:

# Jalanin container dengan custom config
docker run \\
  -e APP_NAME="BuildWithAngga - Local Dev" \\
  -e SHOW_PROMO_BANNER=false \\
  -e SMTP_HOST="smtp.gmail.com" \\
  buildwithangga-app

Kalo banyak environment variables, kalian bisa bikin file .env:

# .env file
APP_NAME=BuildWithAngga Course Platform
SHOW_PROMO_BANNER=true
SMTP_HOST=smtp.buildwithangga.com
[email protected]
SMTP_PASS=secret123

Terus jalanin container dengan:

docker run --env-file .env buildwithangga-app

Di kode Next.js kalian, tinggal akses kayak gini:

// di pages/index.js atau components
export default function HomePage() {
  const showBanner = process.env.SHOW_PROMO_BANNER === 'true';

  return (
    <div>
      {showBanner && (
        <div className="promo-banner">
          Diskon 50% semua course BuildWithAngga!
        </div>
      )}
      <h1>{process.env.APP_NAME}</h1>
    </div>
  );
}

Tips penting buat pemula:

  • Jangan masukkan password atau API key langsung di Dockerfile
  • Kasih nilai default yang masuk akal buat yang gak sensitif
  • Pake nama yang jelas dan konsisten buat environment variables

Satu lagi tip penting: validate environment variables di startup aplikasi. Ini memastikan container fail fast kalo ada misconfiguration:

// validate.js
const requiredEnvs = [
  'DATABASE_URL',
  'BUILDWITHANGGA_API_KEY'
];

requiredEnvs.forEach(env => {
  if (!process.env[env]) {
    console.error(`Missing required environment variable: ${env}`);
    process.exit(1);
  }
});

Troubleshooting Common Issues

Sebelum kita lanjut ke section berikutnya, gue mau bahas beberapa masalah yang sering muncul pas bikin dan jalanin Dockerfile optimized ini, beserta solusinya.

Error: npm ci sync issues

Kalo kalian dapet error kayak:

npm error `npm ci` can only install packages when your package.json and package-lock.json are in sync

Ini terjadi karena package-lock.json kalian outdated atau gak match dengan package.json. Solusinya:

Hapus package-lock.json dan node_modules di local:

rm -rf node_modules package-lock.json
npm install

Terus commit package-lock.json yang baru, atau pake npm install instead of npm ci dalam Dockerfile kayak yang udah gue update di contoh di atas.

Error: File not found saat copy

Kalo kalian dapet error kayak:

"/app/next.config.js": not found

Ini terjadi karena Docker nyoba copy file yang gak ada di project kalian. Solusinya:

Pilihan 1: Bikin file yang kosong dulu Kalo kalian gak punya next.config.js, bikin file kosong:

touch next.config.js

Pilihan 2: Pake wildcard pattern Ganti COPY command jadi:

COPY --from=builder /app/next.config.* ./

Dengan pattern *, Docker bakal copy file yang ada aja, gak error kalo gak ada.

Pilihan 3: Skip copy file yang gak perlu Kalo project kalian gak butuh next.config.js, hapus aja baris COPY tersebut dari Dockerfile.

Error: Permission denied

Kalo dapet permission error, pastikan kalian jalanin Docker dengan proper permissions, atau tambahkan user setup di Dockerfile kayak yang udah kita discuss.

Error: Build context too large

Kalo Docker complain tentang build context yang terlalu besar, pastikan kalian punya .dockerignore file yang proper buat exclude file-file yang gak perlu.

Container exit immediately

Kalo container langsung exit setelah start, cek logs dengan:

docker logs <container-name>

Biasanya ini karena ada error dalam aplikasi atau command yang salah.


Build dan Run Docker Image

Nah, sekarang kita masuk ke bagian yang paling exciting nih - saatnya build dan jalanin Docker image yang udah kita buat! Ini adalah momen dimana semua teori dan kode Dockerfile yang udah kita tulis bakal jadi aplikasi yang bener-bener running. Gue tau kalian pasti udah gak sabar buat ngeliat hasil karya kalian hidup dan bisa diakses lewat browser.

Di bagian ini, kita bakal explore semua aspek dari build process, mulai dari perintah dasar sampe teknik-teknik advanced buat monitoring dan troubleshooting. Gue juga bakal kasih tips-tips praktis yang biasa dipake di real-world development, jadi kalian gak cuma tau cara basicnya aja, tapi juga best practices yang bakal berguna banget di karir kalian nanti.

Building Docker image

Building Docker image adalah proses mengubah Dockerfile dan source code kalian jadi sebuah executable image yang bisa di-deploy dimana aja. Proses ini kayak compile aplikasi, tapi hasil akhirnya adalah complete package yang berisi semua yang dibutuhin buat jalanin aplikasi BuildWithAngga kalian.

Perintah docker build

Perintah paling dasar buat build Docker image adalah docker build. Mari kita mulai dengan contoh yang simple dulu. Pastikan kalian ada di direktori yang sama dengan Dockerfile, terus jalanin perintah ini:

docker build .

Titik di akhir itu penting banget - ini kasih tau Docker bahwa build context adalah direktori sekarang. Build context adalah semua file dan folder yang bisa diakses Docker selama proses build. Jadi basically, Docker bakal kirim semua isi folder ke Docker daemon buat diproses.

Tapi build kayak gini gak kasih nama ke image, jadi imagenya bakal punya nama yang random kayak <none>:<none>. Ini gak praktis banget buat development. Makanya kita perlu kasih tag atau nama yang proper.

Kalian juga bisa spesifik lokasi Dockerfile kalo gak ada di direktori sekarang:

docker build -f /path/to/Dockerfile .

Flag -f atau --file memungkinkan kalian specify lokasi Dockerfile yang beda dari default. Ini berguna kalo kalian punya multiple Dockerfiles dalam satu project, misalnya Dockerfile.dev buat development dan Dockerfile.prod buat production.

Tagging image dengan penamaan yang proper

Tagging adalah cara ngasih nama dan versi ke Docker image. Ini kayak ngasih label yang meaningful, jadi nanti gampang nyari dan manage image-image kalian. Format dasar tagging adalah nama:versi.

docker build -t buildwithangga-nextjs:latest .

Flag -t atau --tag kasih nama ke image. Dalam contoh di atas, nama imagenya adalah buildwithangga-nextjs dengan tag latest. Tag latest adalah default tag yang dipake kalo kalian gak specify tag tertentu.

Kalian juga bisa kasih tag yang lebih spesifik, misalnya pake versi aplikasi:

docker build -t buildwithangga-nextjs:v1.0.0 .

Atau bisa juga pake informasi lain kayak environment atau fitur:

docker build -t buildwithangga-nextjs:development .
docker build -t buildwithangga-nextjs:with-analytics .

Buat project yang lebih complex, kalian bisa pake namespace atau organization name:

docker build -t buildwithangga/course-platform:v2.1.0 .

Format ini berguna banget kalo kalian mau push image ke Docker registry kayak Docker Hub. Namespace buildwithangga bisa jadi username atau organization name kalian.

Kalian juga bisa kasih multiple tags dalam satu build command:

docker build -t buildwithangga-nextjs:latest -t buildwithangga-nextjs:v1.0.0 .

Ini bikin dua tag yang point ke image yang sama, jadi kalian bisa reference image pake nama mana aja yang lebih convenient.

Monitoring build process

Build process Docker bisa take waktu yang lumayan lama, tergantung kompleksitas aplikasi dan kecepatan internet. Penting banget buat understand gimana cara monitor proses ini dan optimize performancenya.

Pas kalian jalanin docker build, kalian bakal lihat output yang detail tentang setiap step:

Sending build context to Docker daemon  15.36MB
Step 1/12 : FROM node:24-alpine
 ---> a1b2c3d4e5f6
Step 2/12 : WORKDIR /app
 ---> Running in 1234567890ab
Removing intermediate container 1234567890ab
 ---> 9876543210cd
Step 3/12 : COPY package*.json ./
 ---> 2468135790ef
...

Build Docker Image
Build Docker Image

Setiap step correspond dengan satu instruksi dalam Dockerfile kalian. Docker bakal show progress dan ID dari setiap layer yang dibuat. Kalo ada step yang gagal, build process bakal stop dan kasih error message yang detail.

Buat build yang lebih verbose, kalian bisa pake flag --progress:

docker build --progress=plain -t buildwithangga-nextjs .

Flag --progress=plain kasih output yang lebih detail, termasuk real-time output dari perintah RUN. Ini berguna banget buat debugging build issues.

Kalo kalian mau monitor resource usage selama build:

docker stats

Jalanin perintah ini di terminal yang terpisah selama build process. Kalian bakal bisa lihat CPU dan memory usage dari Docker daemon.

Buat build yang lebih quiet, kalian bisa pake flag --quiet atau -q:

docker build -q -t buildwithangga-nextjs .

Ini cuma bakal show image ID akhir, tanpa detail step-by-step. Berguna buat automation scripts dimana kalian gak butuh verbose output.

Menjalankan container

Setelah image berhasil di-build, langkah selanjutnya adalah jalanin container dari image tersebut. Running container adalah proses membuat instance yang aktif dari image, kayak menjalankan program dari file executable.

Perintah docker run

Perintah dasar buat jalanin container adalah docker run. Ini adalah command yang paling sering dipake dalam Docker development workflow.

docker run buildwithangga-nextjs

Perintah ini bakal create dan start container baru dari image buildwithangga-nextjs. Tapi ada masalah - container bakal jalan di foreground dan block terminal kalian. Plus, kalian gak bisa akses aplikasi dari luar container karena port belum di-map.

Docker run container
Docker run container

Buat jalanin container di background (detached mode), pake flag -d:

docker run -d buildwithangga-nextjs

Sekarang container bakal jalan di background dan kalian bisa continue pake terminal buat hal lain. Docker bakal return container ID yang panjang, tapi kalian gak perlu ngapalin ini.

Buat kasih nama ke container supaya gampang diingat:

docker run -d --name buildwithangga-app buildwithangga-nextjs

Flag --name kasih nama yang meaningful ke container. Sekarang kalian bisa reference container pake nama buildwithangga-app instead of ID yang panjang.

Port mapping dengan flag -p

Aplikasi Next.js di dalam container listen di port 3000, tapi port ini gak bisa diakses dari luar container secara default. Kalian perlu map port dalam container ke port di host machine pake flag -p.

docker run -d -p 3000:3000 --name buildwithangga-app buildwithangga-nextjs

Format flag -p adalah host_port:container_port. Dalam contoh di atas, port 3000 di komputer kalian bakal di-forward ke port 3000 di dalam container.

Kalian juga bisa map ke port yang beda:

docker run -d -p 8080:3000 --name buildwithangga-app buildwithangga-nextjs

Sekarang aplikasi bisa diakses di http://localhost:8080, meskipun di dalam container masih listen di port 3000.

Jalan serveer di port 8080
Jalan serveer di port 8080
Docker logs
Docker logs

Buat bind ke specific network interface:

docker run -d -p 127.0.0.1:3000:3000 --name buildwithangga-app buildwithangga-nextjs

Ini cuma allow akses dari localhost, gak dari network lain. Berguna buat security di production environment.

Kalian juga bisa map multiple ports:

docker run -d -p 3000:3000 -p 9229:9229 --name buildwithangga-app buildwithangga-nextjs

Port 9229 biasanya dipake buat Node.js debugging.

Volume mounting buat development

Volume mounting memungkinkan kalian share file antara host machine dan container. Ini super berguna buat development, karena kalian bisa edit kode di host dan perubahan langsung keliatan di container tanpa rebuild.

docker run -d -p 3000:3000 -v $(pwd):/app --name buildwithangga-dev buildwithangga-nextjs npm run dev

Flag -v atau --volume dengan format host_path:container_path mount direktori dari host ke container. $(pwd) adalah current working directory.

Tapi ada masalah dengan approach ini - node_modules di host bisa conflict dengan node_modules di container, apalagi kalo host pake OS yang beda. Solusinya adalah pake anonymous volume buat node_modules:

docker run -d -p 3000:3000 \\
  -v $(pwd):/app \\
  -v /app/node_modules \\
  --name buildwithangga-dev \\
  buildwithangga-nextjs npm run dev

Volume /app/node_modules tanpa host path bakal create anonymous volume yang gak overwrite node_modules dari image.

Buat Windows users, pake format path yang beda:

docker run -d -p 3000:3000 -v "%cd%":/app -v /app/node_modules --name buildwithangga-dev buildwithangga-nextjs npm run dev

Atau kalo pake PowerShell:

docker run -d -p 3000:3000 -v ${PWD}:/app -v /app/node_modules --name buildwithangga-dev buildwithangga-nextjs npm run dev

Testing aplikasi

Setelah container running, langkah selanjutnya adalah testing apakah aplikasi bener-bener jalan dengan baik. Testing di container environment bisa sedikit beda dibanding testing di local machine, jadi ada beberapa teknik khusus yang perlu kalian pahami.

Mengakses aplikasi melalui browser

Kalo container udah running dengan proper port mapping, kalian harusnya bisa akses aplikasi lewat browser. Buka browser dan navigate ke URL yang sesuai dengan port mapping kalian.

Kalo kalian pake port mapping default:

<http://localhost:3000>

Kalo kalian map ke port yang beda:

<http://localhost:8080>

Kalo aplikasi load dengan normal, congratulations! Kalian berhasil dockerize aplikasi Next.js. Kalian harusnya bisa lihat halaman BuildWithAngga course platform dengan semua fitur yang biasanya ada.

Tapi kalo aplikasi gak load atau error, jangan panic. Ada beberapa hal yang perlu di-check:

Pertama, pastikan container bener-bener running:

docker ps

Kalian harusnya lihat container dengan status "Up". Kalo gak ada atau statusnya "Exited", berarti ada masalah.

Kedua, check port mapping. Pastikan port yang kalian pake di browser sama dengan yang di-specify di docker run command.

Ketiga, pastikan aplikasi di dalam container listen di 0.0.0.0, bukan cuma 127.0.0.1 atau localhost. Next.js biasanya udah handle ini secara otomatis, tapi worth checking.

Checking logs dengan docker logs

Logs adalah tool debugging yang paling powerful buat troubleshoot container issues. Docker capture semua output yang dikirim ke stdout dan stderr dari aplikasi di dalam container.

docker logs buildwithangga-app

Perintah ini bakal show semua logs dari container sejak container start. Kalian harusnya lihat output kayak:

> [email protected] start
> next start

- ready started server on 0.0.0.0:3000, url: <http://localhost:3000>

Kalo ada error, kalian bakal lihat error message yang detail di sini.

Buat follow logs secara real-time:

docker logs -f buildwithangga-app

Flag -f atau --follow bakal show logs secara real-time, kayak tail -f di Linux. Ini berguna banget buat monitor aplikasi yang lagi running.

Buat limit jumlah lines yang ditampilin:

docker logs --tail 50 buildwithangga-app

Flag --tail bakal show 50 baris terakhir aja. Berguna kalo logs udah sangat panjang.

Buat show logs dalam timeframe tertentu:

docker logs --since 2025-08-04T10:00:00 buildwithangga-app

Flag --since show logs sejak timestamp tertentu.

Kalo kalian mau search specific pattern dalam logs:

docker logs buildwithangga-app 2>&1 | grep "error"

Ini bakal filter logs dan cuma show lines yang contain kata "error".

Debug common issues

Ada beberapa masalah yang sering muncul pas running Docker containers, especially buat pemula. Gue bakal bahas yang paling common dan gimana cara nge-fix nya.

Container exit immediately

Kalo container langsung exit setelah start, biasanya ada masalah dengan command yang dijalanin atau ada error dalam aplikasi. Check logs buat liat apa yang terjadi:

docker logs buildwithangga-app

Common causes:

  • Command dalam CMD atau ENTRYPOINT salah
  • Dependency yang missing
  • Configuration error
  • Port yang udah dipake process lain

Port already in use

Kalo kalian dapet error "port already in use", berarti ada process lain yang udah pake port tersebut. Solusinya bisa kill process yang pake port itu, atau map ke port lain:

docker run -d -p 3001:3000 --name buildwithangga-app buildwithangga-nextjs

Buat check siapa yang pake port tertentu:

lsof -i :3000

Atau di Windows:

netstat -ano | findstr :3000

Permission issues

Kalo ada permission error, especially pas mount volumes, pastikan user dalam container punya permission yang proper. Ini udah kita handle dengan setup user non-root di Dockerfile.

Network connectivity issues

Kalo aplikasi gak bisa connect ke external services (database, APIs, etc), pastikan network configuration udah benar. Buat development, biasanya gak ada masalah, tapi di production perlu setup network yang proper.

Memory atau CPU issues

Kalo aplikasi slow atau container sering restart, mungkin ada resource constraints. Check resource usage:

docker stats buildwithangga-app

Kalian bisa limit resource usage pas run container:

docker run -d -p 3000:3000 --memory="512m" --cpus="1.0" --name buildwithangga-app buildwithangga-nextjs

Entering container untuk debugging

Kalo perlu debug lebih dalam, kalian bisa masuk ke dalam container:

docker exec -it buildwithangga-app /bin/sh

Perintah ini bakal kasih shell access ke container yang lagi running. Kalian bisa explore file system, check processes, dan run commands directly di dalam container.

Kalo container udah exit dan kalian perlu investigate, kalian bisa start container dalam interactive mode:

docker run -it --name debug-container buildwithangga-nextjs /bin/sh

Flag -it enable interactive terminal, dan instead of running aplikasi, kalian langsung masuk ke shell.

Dengan understanding tentang build dan run process ini, kalian udah punya foundation yang solid buat develop dengan Docker. Next step biasanya adalah setup Docker Compose buat manage multiple containers, tapi itu topic buat section selanjutnya. Yang penting sekarang adalah kalian comfortable dengan basic Docker workflow dan bisa troubleshoot common issues yang muncul.


Docker Compose untuk Development

Nah, sekarang kita masuk ke bagian yang bikin hidup developer jadi jauh lebih gampang - Docker Compose! Kalo sebelumnya kita harus manual jalanin berbagai perintah Docker yang panjang dan ribet, sekarang kita bakal belajar gimana cara otomatisasi semua itu dengan satu file konfigurasi yang rapi dan mudah di-maintain.

Docker Compose ini kayak asisten pribadi buat Docker development kalian. Bayangin kalian punya aplikasi BuildWithAngga yang kompleks dengan database, Redis, maybe monitoring tools, dan berbagai service lainnya. Tanpa Docker Compose, kalian harus jalanin belasan perintah docker run dengan parameter yang panjang setiap kali mau develop. Tapi dengan Docker Compose, cukup satu perintah aja dan semua service langsung up dan running dengan konfigurasi yang tepat.

Mengapa menggunakan Docker Compose

Sebelum kita deep dive ke implementation, gue mau jelasin dulu kenapa Docker Compose ini game-changer banget buat development workflow. Ada dua alasan utama yang bikin tool ini jadi must-have buat developer modern.

Pengelolaan multi-container yang disederhanakan

Aplikasi modern itu jarang yang cuma butuh satu container aja. Biasanya kalian punya aplikasi Next.js, database PostgreSQL atau MySQL, maybe Redis buat caching, Elasticsearch buat search functionality, dan mungkin juga monitoring tools kayak Prometheus atau Grafana. Bayangin kalo kalian harus manual setup dan jalanin semua container ini satu per satu setiap kali mau develop.

Tanpa Docker Compose, workflow kalian bakal kayak gini:

# Jalanin database
docker run -d --name postgres-db -e POSTGRES_PASSWORD=secret -p 5432:5432 postgres:13

# Jalanin Redis
docker run -d --name redis-cache -p 6379:6379 redis:alpine

# Jalanin aplikasi Next.js dengan dependencies
docker run -d --name buildwithangga-app \\
  --link postgres-db:database \\
  --link redis-cache:redis \\
  -e DATABASE_URL=postgresql://postgres:secret@database:5432/buildwithangga \\
  -e REDIS_URL=redis://redis:6379 \\
  -p 3000:3000 \\
  buildwithangga-nextjs

Ribet banget kan? Plus kalian harus ingat urutan jalanin containernya, parameter-parameter yang kompleks, dan network setup yang proper. Kalo ada yang salah atau lupa, bisa-bisa debug berjam-jam.

Dengan Docker Compose, semua complexity ini di-abstract jadi satu file konfigurasi yang clean dan readable. Kalian cuma perlu jalanin docker-compose up dan semua service langsung jalan dengan konfigurasi yang udah di-define.

Docker Compose juga handle networking secara otomatis. Semua container yang di-define dalam satu docker-compose.yml file bakal bisa communicate satu sama lain pake service name sebagai hostname. Jadi aplikasi Next.js kalian bisa connect ke database pake hostname postgres-db instead of harus tau IP address yang bisa berubah-ubah.

Konfigurasi sebagai kode

Salah satu prinsip DevOps yang paling penting adalah "Infrastructure as Code" atau "Configuration as Code". Docker Compose memungkinkan kalian define semua konfigurasi development environment dalam file yaml yang bisa di-version control, di-share dengan team, dan di-reproduce dengan exact di environment manapun.

File docker-compose.yml ini jadi source of truth buat development environment kalian. Tim baru yang join project bisa langsung clone repository, jalanin docker-compose up, dan boom - mereka punya development environment yang persis sama dengan yang kalian pake. Gak ada lagi masalah "tapi di komputer gue jalan kok".

Konfigurasi ini juga bisa di-customize buat different environments. Kalian bisa punya docker-compose.yml buat development, docker-compose.staging.yml buat staging, dan docker-compose.prod.yml buat production. Setiap environment bisa punya setting yang beda-beda sesuai kebutuhan.

Version control juga memungkinkan kalian track changes dalam development environment. Kalo ada yang break, kalian bisa easily revert ke konfigurasi sebelumnya. Tim juga bisa collaborate dalam improve development setup tanpa takut break environment orang lain.

Membuat docker-compose.yml

Sekarang kita masuk ke praktik bikin file docker-compose.yml yang proper buat aplikasi BuildWithAngga. File ini adalah heart dari Docker Compose setup, jadi kita perlu design dengan hati-hati supaya maintainable dan scalable.

Service definition untuk Next.js

Docker Compose pake konsep "services" buat define setiap container yang dibutuhin aplikasi. Service ini basically adalah abstract representation dari container, dengan semua konfigurasinya di-define dalam yaml format yang clean dan readable.

Mari kita mulai dengan service definition yang simple buat aplikasi Next.js:

version: '3.8'

services:
  buildwithangga-app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - PORT=3000
    command: npm run dev

File ini define satu service dengan nama buildwithangga-app. Property build: . kasih tau Docker Compose buat build image dari Dockerfile yang ada di current directory. Ini equivalen dengan docker build . yang udah kita pelajari sebelumnya.

Property ports define port mapping, equivalen dengan flag -p dalam docker run. Format "3000:3000" artinya port 3000 di host di-map ke port 3000 di container.

Property environment define environment variables yang bakal di-pass ke container. Ini cleaner dibanding specify satu per satu dengan flag -e dalam docker run.

Property command override default command yang di-define dalam Dockerfile. Dalam hal ini, kita mau jalanin npm run dev instead of npm start buat development mode dengan hot reloading.

Sekarang kita bisa expand konfigurasi ini buat lebih production-ready:

version: '3.8'

services:
  buildwithangga-app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - PORT=3000
      - DATABASE_URL=postgresql://postgres:buildwithangga123@postgres:5432/buildwithangga_dev
      - REDIS_URL=redis://redis:6379
      - NEXTAUTH_SECRET=your-secret-key-here
      - NEXTAUTH_URL=http://localhost:3000
    command: npm run dev
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

Property build sekarang jadi object yang lebih detail. context specify build context directory, dan dockerfile specify nama Dockerfile kalo beda dari default.

Property depends_on kasih tau Docker Compose bahwa service ini depend on service postgres dan redis. Jadi Docker Compose bakal start database dan Redis dulu sebelum start aplikasi Next.js.

Property restart: unless-stopped kasih tau Docker buat automatically restart container kalo crash, except kalo di-stop secara manual.

Volume mapping untuk hot reload

Salah satu fitur paling penting buat development adalah hot reloading - ability buat automatically reload aplikasi pas ada changes di source code. Tanpa proper volume mapping, setiap kali kalian ubah kode, kalian harus rebuild Docker image dan restart container. Ini sangat inefficient buat development workflow.

Volume mapping memungkinkan kalian share source code antara host machine dan container, jadi changes yang kalian buat di editor langsung reflected di container tanpa rebuild.

version: '3.8'

services:
  buildwithangga-app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
      - /app/.next
    environment:
      - NODE_ENV=development
    command: npm run dev

Volume pertama - .:/app mount current directory di host ke /app directory di container. Ini artinya semua changes di source code bakal langsung visible di container.

Volume kedua - /app/node_modules adalah anonymous volume yang prevent node_modules di host overwrite node_modules di container. Ini penting karena node_modules bisa beda antara host dan container, especially kalo host pake OS yang beda atau architecture yang beda.

Volume ketiga - /app/.next juga anonymous volume buat prevent Next.js build artifacts di host interfere dengan yang di container.

Buat development yang lebih robust, kita bisa tambahin more specific volume mappings:

services:
  buildwithangga-app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
      - /app/.next
      - ./public:/app/public
      - ./src:/app/src
      - ./pages:/app/pages
      - ./components:/app/components
      - ./styles:/app/styles
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true
    command: npm run dev

Mapping specific directories kayak ./src:/app/src kasih control yang lebih granular tentang apa aja yang di-sync. Environment variable CHOKIDAR_USEPOLLING=true improve file watching performance di beberapa OS, especially Windows dan macOS.

Environment variables setup

Environment variables adalah cara yang flexible buat configure aplikasi tanpa hardcode values dalam source code. Docker Compose provide several ways buat handle environment variables dengan clean dan maintainable.

Method pertama adalah define directly dalam docker-compose.yml:

services:
  buildwithangga-app:
    build: .
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://postgres:buildwithangga123@postgres:5432/buildwithangga_dev
      - REDIS_URL=redis://redis:6379
      - NEXTAUTH_SECRET=dev-secret-key-change-in-production
      - BUILDWITHANGGA_API_KEY=api-key-for-dev
      - STRIPE_PUBLISHABLE_KEY=pk_test_development_key
      - STRIPE_SECRET_KEY=sk_test_development_key

Method ini simple dan straightforward, tapi ada masalahnya - sensitive data kayak API keys dan database passwords bakal visible dalam file yang kemungkinan di-commit ke version control.

Method yang lebih secure adalah pake .env file:

services:
  buildwithangga-app:
    build: .
    env_file:
      - .env
      - .env.development

Terus bikin file .env di root project:

NODE_ENV=development
DATABASE_URL=postgresql://postgres:buildwithangga123@postgres:5432/buildwithangga_dev
REDIS_URL=redis://redis:6379
NEXTAUTH_SECRET=dev-secret-key-change-in-production
BUILDWITHANGGA_API_KEY=your-api-key-here
STRIPE_PUBLISHABLE_KEY=pk_test_your_key_here
STRIPE_SECRET_KEY=sk_test_your_key_here

# Feature flags
ENABLE_ANALYTICS=true
ENABLE_CHAT_SUPPORT=false
ENABLE_DARK_MODE=true

# Performance settings
MAX_CONCURRENT_REQUESTS=100
REQUEST_TIMEOUT=30000

File .env ini harus di-add ke .gitignore supaya gak ter-commit ke repository. Tim developer bisa punya copy masing-masing dengan values yang sesuai dengan setup local mereka.

Kalian juga bisa combine both methods:

services:
  buildwithangga-app:
    build: .
    env_file:
      - .env
    environment:
      - NODE_ENV=development
      - PORT=3000

Environment variables yang di-define dalam environment section bakal override values yang ada di .env file.

Running dengan Docker Compose

Setelah docker-compose.yml udah ready, saatnya belajar gimana cara pake Docker Compose buat day-to-day development. Ada beberapa commands yang bakal kalian pake setiap hari, dan understanding workflow yang proper bakal bikin development jadi smooth dan efficient.

Commands: up, down, logs

Command yang paling basic dan sering dipake adalah docker-compose up. Command ini equivalent dengan docker run tapi buat semua services yang di-define dalam docker-compose.yml.

docker-compose up

Command ini bakal:

  • Build images kalo belum ada atau ada changes
  • Create networks buat inter-service communication
  • Create dan start semua containers
  • Attach ke logs dari semua services
docker-compose up
docker-compose up
Next.js di docker
Next.js di docker
Next.js di browser
Next.js di browser

By default, docker-compose up run dalam foreground mode, jadi kalian bakal lihat logs dari semua services dalam satu terminal. Ini bagus buat monitoring, tapi block terminal kalian.

Buat run dalam background (detached mode):

docker-compose up -d

Flag -d atau --detach jalanin semua services di background, jadi kalian bisa continue pake terminal buat hal lain.

Kalo kalian mau force rebuild images sebelum start:

docker-compose up --build

Flag --build memaksa Docker Compose rebuild images even kalo gak ada changes yang detected. Berguna kalo ada issue dengan caching atau kalian mau make sure pake latest code.

Buat stop semua services:

docker-compose down

Command ini bakal:

  • Stop semua running containers
  • Remove containers yang udah stop
  • Remove networks yang dibuat buat services
  • Preserve volumes (data gak ilang)
docker-compose down
docker-compose down

Kalo kalian mau remove volumes juga (hati-hati, data bakal ilang):

docker-compose down -v

Flag -v atau --volumes remove semua volumes yang associated dengan services.

Buat lihat logs dari semua services:

docker-compose logs

docker-compose logs
docker-compose logs

Buat follow logs secara real-time:

docker-compose logs -f

Buat lihat logs dari specific service aja:

docker-compose logs buildwithangga-app

Buat lihat logs dari multiple services:

docker-compose logs buildwithangga-app postgres

Development workflow

Dengan Docker Compose, development workflow jadi much more streamlined dan predictable. Mari kita walk through typical development day dengan Docker Compose.

Morning startup routine:

Pas kalian mulai kerja, cukup jalanin:

docker-compose up -d

Command ini bakal start semua development services di background. Database, Redis, aplikasi Next.js, dan service lainnya bakal up dan running dalam beberapa detik.

Kalo kalian mau monitor logs pas startup:

docker-compose up

Atau start di background terus follow logs:

docker-compose up -d && docker-compose logs -f

(windows)
docker-compose up -d ; docker-compose logs

During development:

Pas kalian develop, semua changes di source code bakal automatically reflected di aplikasi thanks to volume mounting dan hot reloading. Kalian gak perlu restart container atau rebuild images.

Kalo kalian mau restart specific service (misalnya ada issue atau mau test restart behavior):

docker-compose restart buildwithangga-app

Kalo kalian add new dependencies ke package.json, kalian perlu rebuild image:

docker-compose build buildwithangga-app
docker-compose up -d

Atau combine dalam satu command:

docker-compose up --build buildwithangga-app

Debugging:

Kalo ada issue, kalian bisa easily access logs atau shell ke dalam container:

# Lihat logs
docker-compose logs buildwithangga-app

# Masuk ke container buat debugging
docker-compose exec buildwithangga-app /bin/sh

# Jalanin specific command dalam container
docker-compose exec buildwithangga-app npm test

Common Error: Pages atau App Directory Tidak Ditemukan

Salah satu error yang sering muncul adalah:

Error: > Couldn't find any `pages` or `app` directory. Please create one under the project root

Error ini terjadi karena Next.js gak nemuin direktori pages atau app di project root. Ada beberapa penyebab dan solusinya:

Penyebab 1: Volume mapping yang salah Kalo kalian pake volume mapping - .:/app, pastikan kalian ada di direktori yang benar pas jalanin docker-compose up. Working directory harus sama dengan lokasi project Next.js kalian.

Penyebab 2: Struktur project yang gak sesuai Next.js 13+ pake App Router yang butuh direktori app, atau Pages Router yang butuh direktori pages. Pastikan kalian punya salah satu dari direktori ini:

buildwithangga-project/
├── app/           # App Router (Next.js 13+)
│   ├── page.tsx
│   └── layout.tsx
├── pages/         # Pages Router (Next.js 12 dan sebelumnya)
│   └── index.tsx
├── package.json
└── docker-compose.yml

Penyebab 3: WORKDIR di Dockerfile gak sync dengan volume mapping Pastikan WORKDIR di Dockerfile sama dengan volume mapping di docker-compose.yml:

# Di Dockerfile
WORKDIR /app

# Di docker-compose.yml
volumes:
  - .:/app  # Harus match dengan WORKDIR

Solusi:

  • Pastikan ada direktori app atau pages di project root
  • Check working directory pas jalanin docker-compose
  • Verify volume mapping udah benar
  • Kalo perlu, masuk ke container dan check file structure:

Troubleshooting Tips:

Kalo masih ada masalah setelah fix di atas:

Check struktur project:

# Lihat struktur direktori
ls -la

# Pastikan ada direktori pages atau app
ls -la pages/ atau ls -la app/

Restart Docker Compose:

docker-compose down
docker-compose up --build

Verify volume mounting:

# Masuk ke container dan check isi direktori
docker-compose exec buildwithangga-app ls -la /app

Kalo direktori kosong atau gak ada file Next.js, berarti volume mapping bermasalah.

End of day cleanup:

Pas selesai kerja, kalian bisa stop semua services:

docker-compose down

Ini bakal free up resources di komputer kalian. Kalo kalian mau keep data (databases, etc), jangan pake flag -v.

Working dengan tim:

Kalo ada team member yang update docker-compose.yml atau ada changes di dependencies:

git pull
docker-compose build
docker-compose up -d

Atau kalo mau make sure everything fresh:

git pull
docker-compose down
docker-compose build --no-cache
docker-compose up -d

Advanced workflow tips:

Buat project yang lebih complex, kalian mungkin mau run specific services aja:

# Cuma jalanin database dan Redis
docker-compose up -d postgres redis

# Jalanin aplikasi dalam development mode
docker-compose up buildwithangga-app

Kalian juga bisa override specific configurations tanpa modify docker-compose.yml:

# Override port mapping
docker-compose up -d -p 8080:3000

# Override environment variable
docker-compose up -d -e NODE_ENV=production

Buat testing production-like environment:

# Jalanin dengan production command
docker-compose run --rm buildwithangga-app npm start

# Build production image dan test
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build

Dengan Docker Compose, kalian punya development environment yang consistent, reproducible, dan easy to manage. Semua complexity dari multi-container setup di-abstract away, jadi kalian bisa focus di actual development instead of fighting dengan infrastructure setup.

Yang paling penting adalah Docker Compose ini scale dengan project kalian. Mulai dari simple single-service setup sampe complex microservices architecture dengan puluhan services, Docker Compose bisa handle semuanya dengan approach yang consistent. Plus, skills yang kalian develop dengan Docker Compose ini directly transferable ke production orchestration tools kayak Kubernetes.


Penutup

Nah, gimana? Udah kebayang kan sekarang cara bikin Docker image untuk aplikasi Next.js kamu? Sebenarnya nggak terlalu ribet kok, cuma butuh beberapa langkah aja.

Kita udah bahas mulai dari setup awal, bikin Dockerfile yang proper, sampai cara optimasi image supaya lebih ringan dan cepat. Yang paling penting adalah kamu udah tau cara containerize aplikasi Next.js kamu dengan Docker, yang artinya deployment jadi lebih mudah dan konsisten di berbagai environment.

Docker memang tools yang super powerful buat developer. Dengan Docker, kamu nggak perlu worry lagi sama "eh, di laptop gue jalan tapi di server nggak jalan" – karena semua dependency udah ke-bundle rapi dalam container. Plus, scaling aplikasi juga jadi lebih gampang nantinya.

Yang paling keren, sekarang aplikasi kamu udah production-ready dan siap di-deploy ke mana aja – mulai dari VPS sederhana sampai cloud platform kayak AWS, Google Cloud, atau Digital Ocean. Tinggal docker run aja, boom! Aplikasi langsung jalan.

Ingat ya, practice makes perfect. Jangan cuma baca doang, tapi langsung coba implementasi di project kamu sendiri. Eksperimen dengan berbagai konfigurasi Docker, coba optimization yang berbeda-beda, dan jangan takut error – itu bagian dari proses belajar.

Lanjut Belajar di BuildWithAngga

Kalau kamu pengen deep dive lebih dalam lagi soal Docker, containerization, atau bahkan DevOps secara keseluruhan, gue highly recommend banget buat cek course-course di BuildWithAngga.

Di sana ada banyak banget course premium yang bahas topik-topik advanced kayak:

  • Docker & Kubernetes untuk Production
  • CI/CD Pipeline dengan GitHub Actions
  • Cloud Deployment Strategy
  • Backend Architecture dengan Microservices
  • Dan masih banyak lagi!

Yang paling gue suka dari BuildWithAngga tuh materinya selalu up-to-date dengan industry standards dan dijelasin dengan bahasa yang gampang dimengerti. Perfect banget buat level up skill development kamu ke tahap yang lebih advanced.

Jadi, tunggu apa lagi? Yuk lanjut belajar dan jadi developer yang lebih kece!