arizonagunlist.com – “Di komputer saya jalan, kok di server error?” Hampir setiap developer pernah mengalaminya. Versi runtime berbeda, library sistem tidak ada, atau konfigurasi yang terlewat. Docker dibuat untuk mengurangi masalah semacam ini dengan membungkus aplikasi beserta kebutuhannya ke dalam satu paket yang berjalan sama di mana pun Docker tersedia.
Artikel ini membahas konsep dasarnya, lalu membawa Anda membuat dan menjalankan satu aplikasi kecil dalam kontainer, memakai Docker Compose, dan menghindari kesalahan pemula. Contoh kodenya sengaja kecil agar fokus pada Docker, bukan bahasa pemrogramannya.
Apa itu Docker, dalam satu paragraf
Menurut dokumentasi resmi Docker, Docker adalah platform terbuka untuk mengembangkan, mengirim, dan menjalankan aplikasi. Aplikasi dikemas ke dalam kontainer sehingga berjalan dengan cara yang sama di berbagai lingkungan, tanpa bergantung pada apa yang terpasang di komputer host. Kontainer terisolasi satu sama lain dan dari host secara bawaan, memakai namespace Linux.
Empat istilah yang perlu dipahami
| Istilah | Artinya | Catatan dari dokumentasi |
|---|---|---|
| Image | Paket berisi file, biner, library, dan konfigurasi yang dibutuhkan untuk menjalankan kontainer | Bersifat tidak bisa diubah (immutable); tersusun dari lapisan (layer) |
| Kontainer | Instans image yang sedang berjalan | Data yang tidak disimpan di penyimpanan persisten hilang saat kontainer dihapus |
| Dockerfile | Berkas berisi instruksi untuk membangun image | Tiap instruksi menambah satu layer |
| Registry | Tempat menyimpan dan membagikan image | Docker Hub adalah registry publik bawaan |
Cara cepat mengingatnya: image seperti cetakan, kontainer adalah barang yang dicetak darinya, dan Dockerfile adalah resep membuat cetakannya.
Dokumentasi juga menjelaskan arsitekturnya: perintah docker adalah klien yang mengirim permintaan ke daemon (dockerd), yang mengelola image, kontainer, jaringan, dan volume.
Langkah 1: Siapkan aplikasi contoh
Saya membuat aplikasi Node.js sederhana yang membalas satu kalimat. Berkas ini saya jalankan langsung di sandbox untuk memastikan responsnya benar.
package.json:
{
"name": "halo-docker",
"version": "1.0.0",
"main": "server.js",
"scripts": { "start": "node server.js" }
}
server.js:
const http = require("http");
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end("Halo dari dalam kontainer!\n");
});
server.listen(port, "0.0.0.0", () => {
console.log(`Server berjalan di port ${port}`);
});
Perhatikan "0.0.0.0". Di dalam kontainer, server yang hanya mendengarkan 127.0.0.1 tidak akan terjangkau dari luar. Panduan Next.js di dokumentasi Docker juga mengatur HOSTNAME="0.0.0.0" agar server dapat diakses dari luar kontainer.
Langkah 2: Tulis Dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY . .
ENV PORT=3000
EXPOSE 3000
USER node
CMD ["node", "server.js"]
Penjelasan singkat:
FROMmenentukan image dasar. Dokumentasi menyebut Anda bisa mulai dari image dasar seperti Python atau Node.js lalu menambahkan layer sendiri.COPY package*.json ./laluRUN npm installdilakukan sebelum menyalin seluruh kode. Karena setiap instruksi adalah layer dan Docker hanya membangun ulang layer yang berubah (menurut dokumentasi), urutan ini membuat dependensi tidak diunduh ulang selamapackage.jsontidak berubah. Penjelasan urutan cache ini adalah praktik umum, bukan kutipan langsung dari halaman yang saya baca.USER nodemenjalankan aplikasi sebagai pengguna non-root, praktik yang juga dipakai panduan Next.js di dokumentasi Docker.EXPOSEbersifat dokumentasi port; pemetaan port sebenarnya dilakukan saatdocker run.
Buat juga .dockerignore:
node_modules
npm-debug.log
.git
.env
Dockerfile
compose.yaml
Dokumentasi menyebut .dockerignore menjaga konteks build tetap kecil dan mencegah berkas sensitif seperti .env dan .git masuk ke image. Contoh di panduan Next.js juga mengecualikan node_modules.
Langkah 3: Bangun dan jalankan
docker build --tag halo-docker .
docker run -p 8080:3000 halo-docker
--tag (atau -t) memberi nama pada image, dan titik di akhir menentukan konteks build, yaitu direktori saat ini. Dalam -p 8080:3000, angka pertama adalah port di komputer Anda dan angka kedua adalah port di dalam kontainer. Panduan Docker memakai pola yang sama, misalnya -p 3000:3000, dan mencatat bahwa pemetaan harus cocok dengan port yang didengarkan server.
Setelah kontainer berjalan, buka http://localhost:8080. Anda seharusnya melihat “Halo dari dalam kontainer!”.
Perintah lain yang sering dipakai, misalnya menjalankan di latar belakang dengan nama:
docker run -d -p 8080:3000 --name halo-app halo-docker
docker stop halo-app
Pola -d, --name, dan docker stop sama dengan contoh di panduan Docker. Untuk melihat kontainer berjalan dan log-nya, biasanya dipakai docker ps dan docker logs halo-app; dua perintah ini umum dikenal, tetapi tidak dari halaman yang saya baca langsung.
Catatan penting soal pengujian: di sandbox tempat artikel ini disusun, klien Docker tersedia tetapi daemon tidak berjalan, jadi saya tidak bisa membangun image atau menjalankan kontainer. Yang saya verifikasi: aplikasi Node berjalan dan membalas dengan benar, serta sintaks Dockerfile dan berkas Compose valid. Jalankan sendiri docker build di mesin Anda untuk memastikan.
Langkah 4: Simpan data dengan volume, bukan di kontainer
Saat kontainer dihapus, data di dalamnya ikut hilang kecuali disimpan di penyimpanan persisten. Dokumentasi Docker menjelaskan dua opsi:
- Volume: cara yang direkomendasikan untuk menyimpan data yang dihasilkan kontainer; data tetap ada walau kontainer dihapus.
- Bind mount: membagikan berkas atau direktori tertentu dari komputer host ke kontainer, cocok untuk pengembangan karena perubahan terlihat langsung.
Contoh sintaks dari dokumentasi:
docker run --mount type=volume,src=data-saya,dst=/app/data halo-docker
docker run -d --name situs -p 8080:80 -v .:/usr/local/apache2/htdocs/ httpd:2.4
Dokumentasi menyarankan memakai --mount karena lebih eksplisit, dan mencatat bahwa -v membuat direktori host otomatis jika belum ada, sedangkan --mount gagal dengan pesan galat. Volume yang tidak terpakai tetap ada sampai dihapus, misalnya dengan docker volume prune.
Langkah 5: Jalankan beberapa layanan dengan Docker Compose
Aplikasi nyata jarang berdiri sendiri; ada database, cache, dan lainnya. Docker Compose memakai satu berkas YAML untuk mendefinisikan aplikasi multi-kontainer. Menurut dokumentasi, berkas bawaannya compose.yaml (disarankan) atau compose.yml, dan model aplikasinya terdiri dari services, networks, volumes, configs, dan secrets.
Contoh minimal untuk aplikasi kita (sintaksnya saya validasi dengan docker compose config):
services:
web:
build: .
ports:
- "8080:3000"
environment:
PORT: "3000"
Perintah utama dari dokumentasi:
docker compose up # menjalankan semua layanan
docker compose ps # melihat status layanan
docker compose logs # melihat log
docker compose down # menghentikan dan menghapus layanan
Ketika Anda menambah layanan lain (misalnya database), Compose menaruh semuanya di satu jaringan sehingga layanan dapat berkomunikasi lewat nama layanan. Detail jaringan dan depends_on tidak saya telusuri dalam artikel ini.
Mengapa ini membuat lingkungan lebih konsisten?
- Versi runtime ditetapkan di
FROM, bukan bergantung pada apa yang terpasang di laptop atau server. - Dependensi aplikasi diinstal di dalam image, sehingga semua orang menjalankan paket yang sama.
- Konfigurasi dapat dikirim lewat
ENVatau variabel lingkungan, bukan dengan mengubah sistem host.
Ini keuntungan nyata, tetapi bukan jaminan hasil identik di setiap kondisi. Perbedaan arsitektur CPU, versi kernel, dan konfigurasi jaringan host masih bisa memengaruhi perilaku.
Kesalahan umum developer pemula
| Kesalahan | Dampak | Perbaikan |
|---|---|---|
Server hanya mendengarkan localhost di dalam kontainer |
Aplikasi tidak bisa diakses dari luar | Dengarkan 0.0.0.0 |
Salah memetakan port (-p) |
Halaman tidak terbuka | Port kedua harus sama dengan port aplikasi di dalam kontainer |
| Menyalin semua berkas sebelum install dependensi | Cache layer tidak efektif, build lambat | Salin package*.json dulu, install, lalu salin kode |
Tidak memakai .dockerignore |
Image besar, risiko .env dan .git ikut masuk |
Buat .dockerignore |
| Menyimpan data penting di dalam kontainer | Data hilang saat kontainer dihapus | Gunakan volume |
| Menjalankan sebagai root | Risiko keamanan lebih besar | Gunakan USER non-root |
Memakai tag latest tanpa sadar |
Versi bisa berubah saat ditarik ulang | Tetapkan tag versi yang spesifik (saran penulis; dokumentasi hanya menyebut latest sebagai bawaan saat tag tidak ditulis) |
| Memasukkan rahasia ke dalam image | Rahasia ikut tersebar bersama image | Jangan menaruhnya di Dockerfile; gunakan variabel lingkungan atau fitur secrets |
Pertanyaan yang sering muncul
Apa bedanya Docker dengan mesin virtual?
Dokumentasi menyebut Docker ringan dan cepat serta alternatif hemat biaya dibanding mesin virtual berbasis hypervisor, tanpa membahas perbedaannya lebih jauh. Untuk perbandingan teknis rinci, rujuk dokumentasi atau sumber khusus.
Apakah Docker dan Docker Compose sama?
Tidak. Compose adalah klien lain yang dipakai untuk aplikasi multi-kontainer, menurut dokumentasi.
Data saya hilang setelah kontainer dihapus. Kenapa?
Itu perilaku normal; data yang tidak berada di penyimpanan persisten hilang. Gunakan volume.
Haruskah memakai volume atau bind mount?
Dokumentasi menyarankan volume untuk persistensi data dan bind mount untuk berbagi berkas host, misalnya saat pengembangan.
Apakah perlu multi-stage build?
Untuk aplikasi kecil mungkin tidak. Panduan Next.js di dokumentasi Docker memakai tiga tahap (dependencies, builder, runner) agar image akhir hanya berisi yang dibutuhkan saat berjalan. Pertimbangkan saat ukuran image dan keamanan mulai penting.

Leave A Comment