Category: Docker

  • Cara Masuk ke Container: docker exec, logs, dan Debugging

    Cara Masuk ke Container: docker exec, logs, dan Debugging

    Cara masuk ke container yang sedang jalan adalah dengan perintah docker exec -it nama_container bash. Kalau image-nya berbasis Alpine dan tidak punya bash, ganti dengan docker exec -it nama_container sh. Setelah itu kamu berada di dalam shell container, bisa lihat file, cek proses, dan edit konfigurasi seperti di server biasa.

    Artikel ini bagian kelima dari seri Belajar Docker dari Nol. Di sini kita bahas docker exec masuk container secara praktik: masuk ke container nginx, cari dan edit file konfigurasinya, lalu reload tanpa restart. Kita juga bahas cara memantau aplikasi lewat docker logs dan docker stats, mengambil file dengan docker cp, plus error klasik bash not found yang hampir pasti kamu temui.

    Di proyek klien, tim Arrazy hampir setiap hari memakai kombinasi exec dan logs ini untuk debug backend Go dan Laravel yang jalan di container. Ini skill dasar yang kepakai terus sampai level production.

    Prasyarat Sebelum Mulai

    Tutorial ini memakai Docker Engine 27.x di Ubuntu 24.04. Perintahnya sama persis di Windows dan macOS yang memakai Docker Desktop. Cek versimu dulu:

    docker --version

    Output yang diharapkan kurang lebih seperti ini:

    Docker version 27.5.1, build 9f9e405

    Kamu juga perlu paham konsep menjalankan container di background dan port mapping. Kalau belum, baca dulu bagian sebelumnya: Docker Port Mapping, Mode Detach, dan Environment Variable.

    docker exec -it: Masuk ke Shell Container yang Sedang Jalan

    Perintah docker exec menjalankan perintah tambahan di dalam container yang sudah berjalan. Formatnya:

    docker exec [opsi] nama_container perintah

    Dua opsi yang hampir selalu dipakai bersamaan:

    • -i (interactive): menjaga input tetap terbuka, jadi apa yang kamu ketik diteruskan ke container
    • -t (tty): memberi terminal virtual, jadi tampilannya seperti terminal normal lengkap dengan prompt

    Digabung jadi -it. Tanpa keduanya, shell memang jalan tapi kamu tidak bisa mengetik apa-apa. Contoh paling umum:

    docker exec -it web bash

    Perintah ini membuka shell bash di dalam container bernama web. Untuk keluar, ketik exit atau tekan Ctrl+D. Container tetap jalan setelah kamu keluar, karena yang berhenti hanya proses bash yang tadi kamu buka, bukan proses utama container.

    Bedanya docker exec dan docker run

    Pemula sering menukar dua perintah ini. Padahal fungsinya beda jauh:

    Aspek docker run docker exec
    Fungsi Membuat container baru dari image Menjalankan perintah di container yang sudah jalan
    Butuh apa Image Container berstatus running
    Efek Muncul container baru di docker ps Tidak ada container baru
    Contoh kasus Start nginx pertama kali Cek isi file config nginx yang sedang jalan

    Jadi kalau kamu menjalankan docker run -it nginx bash dengan niat “masuk ke nginx yang tadi”, yang terjadi justru Docker membuat container nginx kedua yang terpisah total. File yang kamu ubah di situ tidak akan berpengaruh ke container pertama. Ini sumber kebingungan yang sangat sering terjadi.

    Praktik: Masuk ke Container Nginx dan Edit Konfigurasinya

    Biar nempel, kita praktik langsung. Jalankan nginx versi 1.27 di background dengan port mapping:

    docker run -d --name web -p 8080:80 nginx:1.27

    Pastikan jalan:

    docker ps

    Kolom STATUS harus menunjukkan Up. Sekarang masuk ke dalamnya:

    docker exec -it web bash

    Prompt kamu berubah jadi seperti ini, tanda kamu sudah di dalam container:

    root@3f2a1b9c7d5e:/#

    Mencari file konfigurasi nginx

    Konfigurasi utama nginx ada di /etc/nginx/nginx.conf, dan konfigurasi per situs ada di /etc/nginx/conf.d/. Cek isinya:

    cat /etc/nginx/conf.d/default.conf

    Kamu akan lihat blok server yang listen di port 80 dan menyajikan file dari /usr/share/nginx/html.

    Edit konfigurasi tanpa editor

    Image nginx resmi itu ramping, tidak ada nano atau vim di dalamnya. Tapi ada sed, jadi kita bisa edit file langsung dari command line. Kita tambahkan header custom supaya perubahannya gampang dibuktikan:

    sed -i 's|listen       80;|listen       80;\n    add_header X-Diedit-Dari "dalam-container";|' /etc/nginx/conf.d/default.conf

    Validasi dulu sebelum reload. Ini kebiasaan wajib biar nginx tidak mati gara-gara typo:

    nginx -t

    Output yang diharapkan:

    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful

    Kalau sudah ok, reload nginx tanpa restart container:

    nginx -s reload

    Keluar dari container dengan exit, lalu tes dari mesin host:

    curl -I http://localhost:8080

    Di antara header respons, kamu akan melihat baris ini:

    X-Diedit-Dari: dalam-container

    Berhasil. Kamu baru saja masuk ke container yang sedang jalan, mengubah konfigurasinya, dan me-reload service tanpa downtime.

    Tidak harus buka shell dulu

    Untuk perintah sekali jalan, kamu tidak perlu masuk shell. Langsung saja:

    docker exec web nginx -t
    docker exec web cat /etc/nginx/conf.d/default.conf

    Pola ini enak dipakai di script atau saat cuma butuh satu informasi cepat.

    Memantau Aplikasi: docker logs, docker stats, dan docker cp

    Masuk ke container itu satu hal. Tapi sebagian besar sesi debugging justru dimulai dari membaca log dari luar.

    docker logs -f –tail: membaca log real time

    Container yang baik menulis log ke stdout dan stderr, dan Docker menangkap semuanya. Lihat log container nginx tadi:

    docker logs web

    Dua opsi yang paling sering dipakai:

    docker logs -f --tail 50 web
    • --tail 50: hanya tampilkan 50 baris terakhir, bukan seluruh riwayat log yang bisa ribuan baris
    • -f (follow): terus menampilkan log baru secara real time, seperti tail -f di Linux

    Coba buka http://localhost:8080 di browser sambil docker logs -f jalan. Setiap request langsung muncul sebagai baris access log baru. Tekan Ctrl+C untuk berhenti mengikuti log. Ini tidak mematikan container, hanya berhenti menonton.

    docker stats: cek pemakaian CPU dan memori

    Aplikasi lambat atau server penuh? Cek konsumsi resource semua container secara live:

    docker stats

    Outputnya kurang lebih:

    CONTAINER ID   NAME   CPU %   MEM USAGE / LIMIT     MEM %   NET I/O       BLOCK I/O   PIDS
    3f2a1b9c7d5e   web    0.00%   4.2MiB / 7.6GiB       0.05%   1.2kB/850B    0B/0B       5

    Dari sini kelihatan container mana yang rakus memori atau CPU. Tekan Ctrl+C untuk keluar. Kalau cuma mau snapshot sekali tanpa tampilan live, pakai docker stats --no-stream.

    docker cp: ambil file dari dalam container

    Kadang kamu butuh menyalin file dari container ke laptop, misalnya file konfigurasi atau log aplikasi yang ditulis ke file. Formatnya docker cp sumber tujuan:

    docker cp web:/etc/nginx/conf.d/default.conf ./default.conf

    File config tadi sekarang ada di folder kerjamu di host. Arah sebaliknya juga bisa, dari host ke container:

    docker cp ./default.conf web:/etc/nginx/conf.d/default.conf

    Setelah menyalin config baru ke dalam, jangan lupa docker exec web nginx -s reload supaya perubahan terbaca.

    Kapan docker exec Cocok untuk Debug, dan Apa Batasnya

    Gunakan docker exec untuk hal-hal yang sifatnya memeriksa dan bereksperimen: cek apakah file environment terbaca, tes koneksi ke database dari dalam container, lihat isi folder, atau coba ubah satu nilai config untuk membuktikan hipotesis. Cepat, tanpa rebuild, tanpa restart.

    Tapi ada satu hal penting yang wajib kamu pahami: semua perubahan lewat exec itu sementara. Perubahan tersimpan di writable layer milik container itu saja, bukan di image. Begitu container dihapus dan dibuat ulang dari image yang sama, misalnya lewat docker rm lalu docker run lagi, semua editanmu hilang dan kondisi kembali seperti bawaan image.

    Jadi alurnya yang sehat seperti ini:

    1. Pakai docker exec untuk menemukan akar masalah dan menguji perbaikan
    2. Setelah terbukti, pindahkan perbaikan itu ke tempat yang permanen: Dockerfile, file yang di-mount lewat volume, atau environment variable
    3. Rebuild atau recreate container, lalu verifikasi ulang

    Di tim Arrazy, aturan mainnya sama saat membangun sistem aplikasi untuk klien: exec hanya untuk investigasi, perbaikan permanen selalu masuk ke Dockerfile atau konfigurasi yang diversion-control. Kalau perbaikan cuma hidup di dalam container, satu kali server restart bisa mengembalikan bug yang sama dan tidak ada yang tahu kenapa.

    Troubleshooting: Error yang Sering Dialami Pemula

    OCI runtime exec failed: bash not found

    Kamu menjalankan docker exec -it nama_container bash lalu muncul:

    OCI runtime exec failed: exec failed: unable to start container process:
    exec: "bash": executable file not found in $PATH: unknown

    Penyebab: image-nya berbasis Alpine Linux, misalnya nginx:1.27-alpine atau redis:7-alpine. Alpine tidak menyertakan bash, adanya sh. Solusinya ganti perintahnya:

    docker exec -it nama_container sh

    Fungsinya sama saja untuk keperluan debug. Kalau ragu image apa yang dipakai container, cek dengan docker ps di kolom IMAGE.

    Container is not running

    Error response from daemon: container abc123 is not running

    Penyebab: docker exec hanya bisa dipakai ke container yang statusnya running. Kalau container-nya sudah exit, tidak ada proses yang bisa ditumpangi. Cek statusnya dengan docker ps -a. Kalau statusnya Exited, lihat dulu kenapa dia mati lewat docker logs nama_container, perbaiki penyebabnya, lalu start ulang dengan docker start nama_container sebelum exec.

    The input device is not a TTY

    the input device is not a TTY

    Penyebab paling umum: menjalankan docker exec -it dari Git Bash atau MinTTY di Windows, atau dari dalam script otomatis yang tidak punya terminal interaktif. Solusi di Git Bash: awali perintah dengan winpty, jadi winpty docker exec -it web bash. Kalau di dalam script atau cron, buang opsi -t dan jalankan perintah non-interaktif saja, misalnya docker exec web nginx -t.

    docker logs kosong padahal aplikasi jalan

    Kamu menjalankan docker logs tapi tidak ada output sama sekali. Penyebab yang paling sering: aplikasinya menulis log ke file di dalam container, bukan ke stdout/stderr. Docker hanya menangkap stdout dan stderr dari proses utama. Solusinya ada dua: konfigurasi aplikasi supaya log ke stdout (praktik standar untuk container), atau ambil file lognya dengan docker exec -it nama_container sh lalu cat, atau salin keluar pakai docker cp.

    Rangkuman dan Lanjut ke Bagian Berikutnya

    Sekarang kamu punya empat senjata utama untuk berurusan dengan container yang sedang jalan: docker exec -it untuk masuk ke shell, docker logs -f --tail untuk membaca log real time, docker stats untuk memantau resource, dan docker cp untuk memindahkan file. Kamu juga sudah paham kenapa perubahan lewat exec hilang setelah container dibuat ulang, dan kapan harus memindahkan perbaikan ke Dockerfile.

    Bagian berikutnya dari seri ini membahas “Mengelola Docker Image: Pull, Tag, dan Docker Hub”. Di sana kita bedah cara kerja tag image, kenapa latest itu jebakan, dan cara menyimpan image buatanmu sendiri. Artikelnya terbit menyusul, pantau daftarnya di halaman hub Belajar Docker.

    Referensi

  • Docker Port Mapping, Mode Detach, dan Environment Variable

    Docker Port Mapping, Mode Detach, dan Environment Variable

    Container Docker berjalan di jaringan terisolasi, jadi aplikasi di dalamnya tidak otomatis bisa diakses dari browser atau curl di komputermu. Supaya bisa diakses, kamu harus publish port dengan flag -p host:container saat docker run. Itulah inti docker port mapping. Di artikel ini kita praktikkan langsung: menjalankan dua nginx sekaligus di port 8080 dan 8081, menjalankan container di background dengan -d, memberi nama dengan --name, dan menyuntik konfigurasi lewat environment variable -e.

    Artikel ini bagian keempat dari seri Belajar Docker dari Nol. Tiga bagian sebelumnya membahas instalasi, konsep image vs container, dan perintah dasar. Mulai bagian ini kita masuk ke skill yang benar-benar dipakai sehari-hari saat menjalankan aplikasi web di container.

    Prasyarat Sebelum Mulai

    Kamu butuh Docker yang sudah terpasang dan bisa menjalankan docker run hello-world tanpa error. Di artikel ini saya memakai Docker Engine 27 di Ubuntu 24.04, tapi semua perintah berlaku sama di Docker versi 24 ke atas, termasuk di Docker Desktop untuk Windows dan macOS.

    Kamu juga sebaiknya sudah nyaman dengan docker ps, docker stop, dan docker rm. Kalau belum, baca dulu bagian sebelumnya: Perintah Dasar Docker yang Wajib Dikuasai Pemula.

    Kenapa Container Tidak Bisa Diakses Langsung dari Host

    Coba jalankan nginx tanpa flag apa pun:

    docker run nginx:1.27-alpine

    Log nginx muncul di terminal, artinya web server-nya hidup. Tapi kalau kamu buka http://localhost di browser, hasilnya connection refused. Kenapa?

    Secara default Docker menaruh setiap container di jaringan virtual bernama bridge. Container dapat IP internal sendiri, misalnya 172.17.0.2, dan port 80 yang dibuka nginx hanya hidup di IP internal itu. Host alias komputermu tidak otomatis meneruskan traffic ke sana. Ini disengaja. Isolasi jaringan inilah salah satu alasan container aman dijalankan berdampingan tanpa saling ganggu.

    Jembatan antara dunia luar dan container adalah publish port lewat flag -p. Formatnya selalu:

    -p PORT_HOST:PORT_CONTAINER

    Urutannya sering ketukar, jadi hafalkan: host dulu, baru container. -p 8080:80 artinya port 8080 di komputermu diteruskan ke port 80 di dalam container. Port container mengikuti aplikasinya, nginx memang listen di 80. Port host bebas kamu pilih selama belum dipakai proses lain.

    Tekan Ctrl+C dulu untuk menghentikan nginx percobaan tadi sebelum lanjut.

    Praktik Docker Port Mapping: Dua Nginx di Port 8080 dan 8081

    Satu image bisa dijalankan menjadi banyak container sekaligus, asalkan port host-nya berbeda. Kita buktikan dengan dua nginx:

    docker run -d --name web-a -p 8080:80 nginx:1.27-alpine
    docker run -d --name web-b -p 8081:80 nginx:1.27-alpine

    Perhatikan: keduanya sama-sama memakai port 80 di dalam container masing-masing. Tidak bentrok, karena tiap container punya jaringan sendiri. Yang tidak boleh kembar hanya port host, makanya satu dapat 8080 dan satunya 8081.

    Cek keduanya jalan:

    docker ps

    Output yang diharapkan kira-kira seperti ini (ID akan berbeda di komputermu):

    CONTAINER ID   IMAGE               COMMAND                  STATUS         PORTS                                     NAMES
    f3a1c2d4e5b6   nginx:1.27-alpine   "/docker-entrypoint.…"   Up 10 seconds  0.0.0.0:8081->80/tcp, [::]:8081->80/tcp   web-b
    a9b8c7d6e5f4   nginx:1.27-alpine   "/docker-entrypoint.…"   Up 15 seconds  0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   web-a

    Verifikasi dengan curl dan docker port

    Tes dari host dengan curl:

    curl -I http://localhost:8080

    Output yang diharapkan:

    HTTP/1.1 200 OK
    Server: nginx/1.27.5
    Content-Type: text/html
    ...

    Ulangi untuk http://localhost:8081, hasilnya harus sama-sama 200 OK. Dua web server hidup berdampingan di satu mesin, dari satu image yang sama, tanpa konfigurasi virtual host apa pun.

    Kalau lupa container mana dipetakan ke port berapa, tidak perlu menebak dari output docker ps yang padat. Ada perintah khusus:

    docker port web-a

    Output yang diharapkan:

    80/tcp -> 0.0.0.0:8080
    80/tcp -> [::]:8080

    Baris 0.0.0.0 untuk IPv4 dan [::] untuk IPv6. Artinya port 8080 terbuka di semua network interface host. Kalau kamu hanya ingin bisa diakses dari mesin sendiri, misalnya database untuk development, batasi ke localhost: -p 127.0.0.1:8080:80. Kebiasaan kecil ini penting saat nanti kamu deploy ke VPS yang IP-nya publik.

    Mode Detach -d dan Memberi Nama dengan –name

    Di perintah praktik tadi kita sudah menyelipkan dua flag baru. Sekarang kita bedah satu per satu.

    Flag -d (detach) menjalankan container di background. Tanpa -d, terminal kamu tersandera oleh log container, dan menutup terminal atau menekan Ctrl+C ikut mematikan container-nya. Dengan -d, Docker hanya mencetak ID container lalu mengembalikan terminal ke kamu:

    $ docker run -d --name web-c -p 8082:80 nginx:1.27-alpine
    7c9e2f1a8b3d5e6f4a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f

    Container tetap jalan sampai kamu hentikan sendiri dengan docker stop. Hampir semua service seperti web server, database, dan cache dijalankan dengan mode ini.

    Flag --name memberi nama yang kamu tentukan sendiri. Tanpa flag ini Docker mengarang nama acak seperti quirky_banzai, lucu tapi menyulitkan. Bandingkan dua perintah ini:

    docker stop quirky_banzai
    docker stop web-a

    Nama yang jelas membuat stop, logs, port, dan perintah lain gampang diketik dan gampang diingat. Satu aturan penting: nama container harus unik. Selama container bernama web-a masih ada, meskipun statusnya sudah exited, kamu tidak bisa membuat container baru dengan nama sama sebelum menghapusnya dengan docker rm web-a.

    Menyuntik Konfigurasi Lewat Environment Variable -e

    Aplikasi yang baik tidak menulis konfigurasi mati di dalam kode. Password database, mode debug, dan URL API biasanya dibaca dari environment variable. Docker mendukung pola ini lewat flag -e NAMA=nilai saat run.

    Bukti paling sederhana, jalankan container Alpine sekali pakai yang tugasnya cuma mencetak environment:

    docker run --rm -e APP_ENV=production -e APP_PORT=3000 alpine:3.20 env

    Output yang diharapkan:

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=b2c3d4e5f6a7
    APP_ENV=production
    APP_PORT=3000
    HOME=/root

    Dua variabel yang kita suntik ikut muncul. Aplikasi apa pun di dalam container bisa membacanya seperti environment variable biasa.

    Contoh yang lebih nyata adalah image resmi database. MySQL misalnya, wajib diberi tahu password root lewat environment variable, kalau tidak dia menolak start:

    docker run -d --name db-latihan \
      -e MYSQL_ROOT_PASSWORD=rahasia123 \
      -e MYSQL_DATABASE=toko_online \
      -p 3306:3306 \
      mysql:8.4

    Perintah di atas menjalankan MySQL 8.4 dengan password root rahasia123 dan langsung membuatkan database bernama toko_online. Variabel apa saja yang dikenali sebuah image selalu tercantum di halaman image tersebut di Docker Hub, jadi biasakan membaca bagian environment variable sebelum memakai image baru.

    Pola konfigurasi lewat environment variable ini bukan sekadar materi latihan. Di Arrazy, backend Go dan Laravel yang kami bangun untuk sistem aplikasi klien membaca semua kredensial dari environment variable, sehingga image yang sama bisa dipakai di server development maupun production hanya dengan mengganti nilai variabelnya.

    Beda EXPOSE di Image dengan -p Saat Run

    Ini sumber salah paham paling sering di topik port. Saat kamu melihat isi sebuah Dockerfile atau halaman Docker Hub, sering ada baris EXPOSE 80. Banyak pemula mengira baris itu yang membuka port ke host. Bukan.

    EXPOSE hanyalah metadata, semacam catatan dari pembuat image: aplikasi di dalam image ini listen di port 80. Dia tidak membuka apa pun ke host. Tanpa -p, container dengan EXPOSE 80 tetap tidak bisa diakses dari luar.

    Aspek EXPOSE (di Dockerfile) -p (saat docker run)
    Kapan ditulis Saat image dibuat Saat container dijalankan
    Efek ke host Tidak ada, hanya dokumentasi Port host benar-benar diteruskan ke container
    Wajib untuk akses dari luar Tidak Ya
    Bisa diubah pengguna image Tidak, sudah tertanam di image Ya, bebas pilih port host tiap run

    Ada satu titik temu antara keduanya: flag -P (huruf besar). Flag ini menyuruh Docker mem-publish semua port yang tercantum di EXPOSE ke port acak di host:

    docker run -d --name web-acak -P nginx:1.27-alpine
    docker port web-acak

    Output yang diharapkan, angka portnya akan berbeda-beda:

    80/tcp -> 0.0.0.0:32768
    80/tcp -> [::]:32768

    Untuk latihan dan production, -p huruf kecil dengan port eksplisit hampir selalu lebih enak karena portnya bisa ditebak. Anggap -P sebagai trivia yang perlu kamu tahu supaya tidak bingung saat menemuinya di tutorial lain.

    Troubleshooting: Error yang Sering Muncul Saat Publish Port

    Error bind: address already in use

    docker: Error response from daemon: failed to set up container networking:
    driver failed programming external connectivity on endpoint web-a:
    failed to bind host port 0.0.0.0:8080: address already in use

    Artinya port host yang kamu minta sudah dipakai proses lain, bisa container lain, bisa aplikasi biasa seperti Apache atau aplikasi Node yang lupa dimatikan. Cari pelakunya dengan:

    sudo ss -ltnp | grep :8080

    Output contohnya:

    LISTEN 0 4096 *:8080 *:* users:(("docker-proxy",pid=51234,fd=7))

    Kalau yang muncul docker-proxy, pelakunya container lain, cek dengan docker ps lalu stop container yang bentrok. Kalau proses biasa, matikan prosesnya atau lebih aman ganti port host-mu, misalnya jadi -p 8090:80. Di Windows dan macOS, gunakan netstat -ano | findstr :8080 (Windows) atau lsof -i :8080 (macOS) untuk mencari proses yang sama.

    Error the container name is already in use

    docker: Error response from daemon: Conflict. The container name "/web-a" is already
    in use by container "a9b8c7d6e5f4". You have to remove (or rename) that container...

    Nama container harus unik, termasuk container yang sudah berhenti. Lihat semuanya dengan docker ps -a, lalu hapus yang lama dengan docker rm web-a. Kalau masih jalan, hentikan dulu dengan docker stop web-a.

    curl connection refused padahal container jalan

    Tiga penyebab paling umum. Pertama, kamu lupa flag -p sama sekali, cek dengan docker port nama-container, kalau outputnya kosong berarti memang tidak ada port yang dipublish, hapus container lalu run ulang dengan -p. Kedua, kamu mengakses port yang salah, misalnya curl localhost:80 padahal mapping-nya 8080:80, yang diakses dari host selalu port sebelah kiri. Ketiga, urutan -p terbalik, -p 80:8080 berbeda makna dengan -p 8080:80.

    Port sudah dipublish tapi aplikasi belum siap

    Khusus database seperti MySQL, docker ps bisa menunjukkan status Up tapi koneksi masih ditolak beberapa detik pertama. Ini bukan masalah port mapping. Proses inisialisasi database memang butuh waktu. Tunggu sebentar dan cek lognya dengan docker logs db-latihan sampai muncul tulisan ready for connections.

    Bersih-bersih dan Lanjut ke Bagian Berikutnya

    Sebelum lanjut, rapikan semua container latihan supaya tidak makan resource:

    docker stop web-a web-b web-c web-acak db-latihan
    docker rm web-a web-b web-c web-acak db-latihan

    Sampai sini kamu sudah pegang empat senjata baru: -p untuk membuka akses dari host ke container, -d untuk menjalankan di background, --name untuk penamaan yang waras, dan -e untuk menyuntik konfigurasi. Kombinasi keempatnya adalah pola docker run yang akan terus kamu pakai sampai bagian akhir seri ini.

    Bagian berikutnya membahas cara masuk ke dalam container yang sedang berjalan: “Cara Masuk ke Container: docker exec, logs, dan Debugging”. Di sana kamu belajar membuka shell di dalam container, membaca log dengan benar, dan mendiagnosis container yang tiba-tiba mati. Artikelnya terbit menyusul, pantau daftar lengkapnya di halaman hub Belajar Docker dari Nol.

    Referensi

  • Perintah Dasar Docker yang Wajib Dikuasai Pemula

    Perintah Dasar Docker yang Wajib Dikuasai Pemula

    Perintah dasar Docker yang benar-benar kamu pakai setiap hari sebenarnya tidak banyak. Intinya ada di daftar ini: docker ps -a untuk melihat semua container, docker images untuk melihat image, docker stop, docker start, dan docker restart untuk mengatur hidup matinya container, docker rm dan docker rmi untuk bersih-bersih, lalu docker logs, docker inspect, dan docker system df untuk memeriksa kondisi. Kuasai belasan perintah ini dan kamu sudah bisa mengelola container harian tanpa panik.

    Artikel ini bagian ketiga dari seri Belajar Docker dari Nol. Kita tidak akan menghafal semua perintah satu per satu. Kita jalankan tiga container sekaligus, periksa kondisinya, lalu bersihkan semuanya dengan urutan yang benar. Cara ini lebih nempel di kepala daripada membaca daftar perintah panjang.

    Prasyarat Sebelum Latihan Perintah Docker

    Pastikan Docker sudah terinstal dan bisa jalan tanpa error. Di tutorial ini saya memakai Docker Engine 28.3 di Ubuntu 24.04, tapi semua perintah di sini sama saja di Windows dengan Docker Desktop atau di macOS. Cek dulu versimu:

    docker --version

    Output yang diharapkan kurang lebih seperti ini:

    Docker version 28.3.2, build 578ccf6

    Kamu juga perlu paham beda image dan container, karena hampir semua perintah di artikel ini menyasar salah satunya. Kalau masih ragu bedanya, baca dulu bagian sebelumnya: Perbedaan Docker Image dan Container + Praktik Pertama. Singkatnya, image itu cetakan, container itu hasil cetakannya yang berjalan.

    Peta Perintah Dasar Docker untuk Pemakaian Harian

    Supaya tidak bingung perintah mana untuk apa, pakai tabel ini sebagai peta. Kolom target penting: banyak pemula tertukar antara perintah untuk container dan perintah untuk image.

    Perintah Target Fungsi
    docker ps Container Melihat container yang sedang berjalan
    docker ps -a Container Melihat semua container, termasuk yang sudah berhenti
    docker images Image Melihat daftar image di komputer
    docker stop Container Menghentikan container yang berjalan
    docker start Container Menyalakan lagi container yang berhenti
    docker restart Container Stop lalu start dalam satu perintah
    docker rm Container Menghapus container yang sudah berhenti
    docker rmi Image Menghapus image yang tidak dipakai container mana pun
    docker logs Container Melihat output aplikasi di dalam container
    docker inspect Keduanya Melihat detail lengkap dalam format JSON
    docker system df Disk Melihat total pemakaian disk oleh Docker

    Pola yang perlu kamu ingat: perintah berakhiran i seperti rmi bekerja pada image. Sisanya kebanyakan bekerja pada container. Urutan hidup container juga selalu sama: dibuat, berjalan, berhenti, dihapus. docker rm hanya mau menghapus container yang sudah di posisi berhenti, dan docker rmi hanya mau menghapus image yang sudah tidak dipakai container mana pun. Urutan ini yang akan kita praktikkan.

    Praktik: Jalankan Tiga Container Sekaligus

    Kita jalankan tiga container dari tiga image berbeda supaya terasa mengelola lebih dari satu layanan, mirip kondisi nyata di server. Jalankan tiga perintah ini satu per satu:

    docker run -d --name web-satu nginx:1.27-alpine
    docker run -d --name cache-satu redis:7.4-alpine
    docker run -d --name web-dua httpd:2.4-alpine

    Opsi -d membuat container berjalan di belakang layar, dan --name memberi nama supaya gampang dipanggil. Detail mode detach kita bahas di bagian berikutnya dari seri ini. Sekarang cek yang sedang berjalan:

    docker ps

    Outputnya kurang lebih begini, tiga baris untuk tiga container:

    CONTAINER ID   IMAGE               COMMAND                  STATUS          NAMES
    f3a1b2c4d5e6   httpd:2.4-alpine    "httpd-foreground"       Up 10 seconds   web-dua
    a9b8c7d6e5f4   redis:7.4-alpine    "docker-entrypoint.s…"   Up 25 seconds   cache-satu
    1c2d3e4f5a6b   nginx:1.27-alpine   "/docker-entrypoint.…"   Up 40 seconds   web-satu

    Sekarang hentikan salah satunya, lalu bandingkan docker ps dengan docker ps -a:

    docker stop web-dua
    docker ps
    docker ps -a

    docker ps hanya menampilkan dua container. Tapi docker ps -a tetap menampilkan tiga, dengan web-dua berstatus Exited (0). Ini konsep yang paling sering bikin pemula bingung: container yang berhenti itu tidak hilang. Dia masih ada di disk, lengkap dengan namanya. Kamu bisa menyalakannya lagi kapan saja:

    docker start web-dua

    Kalau aplikasi di dalam container terasa aneh dan kamu ingin muat ulang, pakai docker restart web-dua. Isinya tetap sama, prosesnya saja yang dimulai ulang.

    Bersihkan Semua Container dengan Urutan yang Benar

    Selesai latihan, bersihkan. Urutannya selalu stop dulu, baru hapus container, baru hapus image kalau memang tidak dibutuhkan lagi:

    docker stop web-satu cache-satu web-dua
    docker rm web-satu cache-satu web-dua
    docker rmi nginx:1.27-alpine redis:7.4-alpine httpd:2.4-alpine

    Perhatikan bahwa satu perintah bisa menerima banyak nama sekaligus. Setelah itu docker ps -a harus kosong dan docker images tidak lagi menampilkan ketiga image tadi. Kalau containermu banyak dan malas mengetik nama satu per satu, ada jurus cepat:

    docker stop $(docker ps -q)
    docker rm $(docker ps -aq)

    Opsi -q artinya quiet, hanya mencetak ID container. Hasilnya disuapkan ke stop dan rm. Hati-hati, perintah ini menyapu semua container di mesinmu, jadi jangan dipakai di server yang ada container pentingnya.

    Membaca Output docker logs dan docker inspect

    Dua perintah ini adalah mata kamu ke dalam container. Di pekerjaan tim Arrazy sehari-hari, saat backend Go atau Laravel milik klien berjalan di container dan ada yang aneh, dua perintah inilah yang pertama kami buka sebelum menebak-nebak. Jalankan satu container lagi untuk mencoba:

    docker run -d --name web-tes nginx:1.27-alpine
    docker logs web-tes

    docker logs menampilkan semua output yang dicetak aplikasi di dalam container. Untuk nginx, kamu akan melihat baris seperti ini:

    /docker-entrypoint.sh: Configuration complete; ready for start up
    2026/07/27 03:15:42 [notice] 1#1: start worker processes

    Kalau container mati mendadak, docker logs biasanya berisi pesan error penyebabnya. Ini tempat pertama untuk mencari petunjuk. Dua opsi yang sering dipakai: docker logs -f web-tes untuk mengikuti log secara live seperti tail -f, dan docker logs --tail 50 web-tes untuk mengambil 50 baris terakhir saja.

    Sementara docker inspect menampilkan konfigurasi dan status lengkap dalam format JSON. Outputnya panjang sekali, jadi biasanya kita ambil bagian tertentu dengan opsi --format:

    docker inspect --format '{{.State.Status}}' web-tes
    docker inspect --format '{{.NetworkSettings.IPAddress}}' web-tes

    Perintah pertama menjawab pertanyaan paling dasar: container ini sebenarnya hidup atau tidak. Outputnya satu kata seperti running atau exited. Perintah kedua mencetak alamat IP internal container, misalnya 172.17.0.2. Dua field lain yang berguna saat debugging: {{.State.ExitCode}} untuk tahu kode keluar container yang mati, dan {{.Config.Env}} untuk melihat environment variable yang aktif di dalamnya.

    Cek Pemakaian Disk dengan docker system df

    Biasakan menjalankan perintah ini sejak awal belajar, karena Docker diam-diam rakus disk. Setiap docker pull menambah image ratusan MB, dan container yang berhenti tetap menyita ruang. Banyak orang baru sadar saat disk server penuh dan aplikasi ikut tumbang.

    docker system df

    Outputnya seperti ini:

    TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
    Images          4         1         512.4MB   463.1MB (90%)
    Containers      2         1         24.5MB    12.1MB (49%)
    Local Volumes   1         0         88.9MB    88.9MB (100%)
    Build Cache     0         0         0B        0B

    Kolom paling penting adalah RECLAIMABLE, yaitu ruang yang bisa kamu ambil kembali karena dipakai oleh image dan container yang menganggur. Kalau angkanya sudah besar, bersihkan dengan:

    docker system prune

    Perintah ini menghapus semua container yang berhenti, network yang tidak terpakai, dan image tanpa tag. Docker akan minta konfirmasi dulu sebelum mengeksekusi. Yang perlu diwaspadai adalah varian docker system prune -a, karena ikut menghapus semua image yang sedang tidak dipakai container, termasuk image yang baru kamu pull dan berencana dipakai nanti.

    Troubleshooting: Error yang Sering Dialami Pemula

    Error “conflict: the container name is already in use”

    docker: Error response from daemon: Conflict. The container name "/web-satu"
    is already in use by container "1c2d3e4f5a6b".

    Penyebabnya hampir selalu sama: kamu pernah menjalankan container dengan nama itu, lalu menghentikannya, dan mengira dia sudah hilang. Padahal container berhenti masih ada dan namanya masih terkunci. Cek dengan docker ps -a, pasti ada container lama dengan nama tersebut. Solusinya pilih salah satu: hapus yang lama dengan docker rm web-satu lalu jalankan ulang, atau nyalakan lagi yang lama dengan docker start web-satu kalau isinya masih relevan.

    Error “cannot remove a running container” Saat docker rm

    Error response from daemon: cannot remove container "web-satu":
    container is running: stop the container before removing or force remove

    Docker menolak menghapus container yang masih hidup, dan itu perilaku yang bagus. Cara aman: docker stop web-satu dulu, baru docker rm web-satu. Ada jalan pintas docker rm -f web-satu yang langsung mematikan paksa lalu menghapus, tapi jadikan ini pilihan terakhir. Kill paksa tidak memberi kesempatan aplikasi menutup koneksi atau menyimpan data dengan rapi, dan itu berisiko untuk container database.

    Error “No such container” Padahal Baru Dibuat

    Biasanya karena dua hal. Pertama, salah ketik nama, cek ejaan persisnya lewat kolom NAMES di docker ps -a. Kedua, container memang gagal dibuat sejak awal karena perintah docker run sebelumnya error, tapi errornya tidak terbaca. Scroll ke atas dan baca pesan dari perintah run terakhirmu.

    Error “image is being used by stopped container” Saat docker rmi

    Error response from daemon: conflict: unable to delete nginx:1.27-alpine (must be forced)
    - image is being used by stopped container 1c2d3e4f5a6b

    Image tidak bisa dihapus selama masih ada container yang lahir darinya, walaupun containernya sudah berhenti. Ingat urutan bersih-bersih: hapus dulu containernya dengan docker rm, baru docker rmi akan berhasil.

    Rangkuman dan Lanjut ke Bagian Berikutnya

    Sampai sini kamu sudah pegang perintah dasar Docker yang dipakai hampir setiap hari: melihat kondisi lewat ps -a, images, logs, dan inspect, mengatur container lewat stop, start, restart, membersihkan lewat rm dan rmi dengan urutan yang benar, plus memantau disk lewat system df. Pola pikirnya sederhana: periksa dulu keadaan, baru bertindak. Kebiasaan yang sama kami pegang saat mengelola sistem aplikasi milik klien di server produksi.

    Di bagian berikutnya, “Docker Port Mapping, Mode Detach, dan Environment Variable”, kita bedah opsi -d, -p, dan -e yang tadi sempat kita pakai tanpa penjelasan mendalam, supaya container-mu bisa diakses dari browser dan dikonfigurasi tanpa mengubah image. Artikelnya terbit menyusul, pantau daftarnya di halaman Belajar Docker dari Nol.

    Referensi

  • Perbedaan Docker Image dan Container + Praktik Pertama

    Perbedaan Docker Image dan Container + Praktik Pertama

    Perbedaan Docker image dan container sebenarnya sederhana. Image adalah paket read-only berisi filesystem, aplikasi, dan konfigurasi yang dibutuhkan untuk menjalankan sebuah program. Container adalah proses yang berjalan dari image itu. Image sifatnya statis, seperti file yang diam di disk. Container sifatnya hidup, punya proses, punya memori, dan bisa dihentikan atau dihapus tanpa menyentuh image aslinya.

    Artikel ini bagian kedua dari seri Belajar Docker dari Nol. Setelah paham konsepnya, kita langsung praktik: menjalankan Nginx di container, melihat prosesnya, membukanya di browser, lalu membedah kenapa ada container yang langsung mati begitu dijalankan.

    Prasyarat: Docker Sudah Terpasang

    Kamu butuh Docker Engine yang sudah jalan di komputermu. Kalau belum, ikuti dulu bagian pertama seri ini: Apa Itu Docker dan Cara Install Docker di Ubuntu & Windows. Semua contoh di sini saya jalankan di Ubuntu 24.04 dengan Docker Engine 27, tapi perintahnya sama persis di Windows dengan Docker Desktop.

    Cek dulu instalasimu:

    docker --version

    Output yang diharapkan kurang lebih seperti ini (angka minor boleh beda):

    Docker version 27.5.1, build 9f9e405

    Analogi Paling Gampang: Image Itu Cetakan, Container Itu Hasil Cetakannya

    Bayangkan cetakan kue. Cetakan itu cuma satu, bentuknya tetap, dan tidak berubah sedikit pun setiap kali dipakai. Dari satu cetakan yang sama, kamu bisa membuat sepuluh kue. Tiap kue berdiri sendiri. Kue pertama boleh kamu makan, kue kedua boleh gosong, cetakannya tetap utuh.

    Docker persis seperti itu. Image adalah cetakannya. Container adalah kuenya. Dari satu image nginx, kamu bisa menjalankan lima container Nginx sekaligus, masing-masing dengan nama, port, dan isi memori sendiri. Menghapus salah satu container tidak berpengaruh apa pun ke image, dan tidak berpengaruh ke container lain.

    Kalau dirangkum dalam tabel:

    Aspek Image Container
    Sifat Read-only, statis Hidup, punya proses yang berjalan
    Analogi Cetakan kue Kue hasil cetakan
    Jumlah Satu image Bisa jadi banyak container
    Disimpan di Disk lokal, hasil pull dari registry Dibuat saat docker run, di atas image
    Kalau dihapus Container baru tidak bisa dibuat darinya Image tetap aman, container lain tetap jalan

    Satu detail teknis yang penting: saat container dibuat, Docker tidak menyalin seluruh isi image. Docker hanya menambahkan satu lapisan tulis (writable layer) tipis di atas image. Semua perubahan file di dalam container terjadi di lapisan ini. Itulah kenapa membuat container itu cepat sekali, hitungan detik, bukan menit seperti menyalakan virtual machine.

    Arsitektur Docker: Client, Daemon, dan Registry

    Sebelum praktik, kenali dulu tiga aktor utama supaya kamu paham apa yang sebenarnya terjadi saat mengetik perintah.

    • Docker client, yaitu perintah docker yang kamu ketik di terminal. Dia tidak menjalankan container sendiri, dia cuma mengirim permintaan.
    • Docker daemon (dockerd), proses yang jalan di background. Dialah yang benar-benar bekerja: membangun image, membuat container, mengatur network dan storage.
    • Registry, gudang image di internet atau server internal. Yang paling populer adalah Docker Hub. Dari sinilah image nginx, mysql, dan lainnya diunduh.

    Saat kamu mengetik docker run nginx, urutan kejadiannya seperti ini:

    1. Client mengirim permintaan ke daemon lewat socket.
    2. Daemon mengecek apakah image nginx sudah ada di disk lokal.
    3. Kalau belum ada, daemon melakukan pull dari registry (Docker Hub) dan menyimpannya di lokal.
    4. Daemon membuat container baru dari image itu, menambahkan writable layer di atasnya.
    5. Daemon menjalankan proses utama container, dalam kasus Nginx yaitu web servernya.

    Pemahaman alur ini kepakai terus sampai level produksi. Di tim Arrazy, alur yang sama persis kami pakai saat men-deploy backend Go dan Laravel milik klien ke server, hanya saja registry-nya kadang privat, bukan Docker Hub.

    Praktik: Menjalankan Nginx di Container Pertamamu

    Cukup teori. Jalankan perintah ini:

    docker run -d -p 8080:80 --name webku nginx:1.27

    Penjelasan singkat flag-nya. -d membuat container jalan di background. -p 8080:80 menyambungkan port 8080 di komputermu ke port 80 di dalam container. --name webku memberi nama supaya gampang dirujuk. Detail lengkap soal port mapping dan mode detach dibahas khusus di bagian 4 seri ini, sekarang cukup pakai dulu.

    Karena ini pertama kali, Docker akan pull image dulu. Outputnya kurang lebih:

    Unable to find image 'nginx:1.27' locally
    1.27: Pulling from library/nginx
    a480a496ba95: Pull complete
    f3ace1b8ce45: Pull complete
    11d6fdd0e8a7: Pull complete
    Digest: sha256:...
    Status: Downloaded newer image for nginx:1.27
    3f9c1d2e8b7a...

    Baris terakhir yang berupa deretan huruf dan angka itu adalah ID container barumu. Sekarang lihat container yang sedang jalan:

    docker ps

    Output yang diharapkan:

    CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                  NAMES
    3f9c1d2e8b7a   nginx:1.27   "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp   webku

    Perhatikan kolom STATUS bertuliskan Up. Artinya container hidup dan proses Nginx sedang berjalan di dalamnya. Sekarang buka browser dan akses http://localhost:8080. Kamu akan melihat halaman default dengan tulisan Welcome to nginx! di bagian atasnya. Kalau lebih suka lewat terminal:

    curl http://localhost:8080

    Responsnya HTML yang diawali <title>Welcome to nginx!</title>. Web server pertamamu di Docker sudah jalan.

    Membuktikan Satu Image Bisa Jadi Banyak Container

    Sekarang buktikan analogi cetakan tadi. Jalankan container kedua dari image yang sama, dengan nama dan port berbeda:

    docker run -d -p 8081:80 --name webku2 nginx:1.27

    Kali ini tidak ada proses pull karena image sudah ada di lokal, jadi container langsung jalan dalam waktu kurang dari satu detik. Cek dengan docker ps, sekarang ada dua container, webku dan webku2, dua-duanya dari image nginx:1.27 yang sama. Buka http://localhost:8081, hasilnya halaman Nginx juga. Satu cetakan, dua kue.

    Siklus Hidup Container: Created, Running, Exited

    Container punya beberapa status utama yang perlu kamu hafal:

    • Created: container sudah dibuat dari image tapi prosesnya belum dijalankan. Terjadi kalau kamu pakai docker create tanpa docker start.
    • Running: proses utama di dalam container sedang berjalan. Inilah yang muncul di docker ps.
    • Exited: proses utamanya sudah berhenti, entah karena selesai, error, atau dihentikan manual.

    Coba hentikan container kedua:

    docker stop webku2

    Lalu jalankan docker ps lagi. Container webku2 hilang dari daftar. Nah, di sinilah banyak pemula bingung: containernya ke mana?

    Jawabannya, container itu tidak hilang. Dia masih ada di disk dengan status Exited, hanya saja docker ps secara default cuma menampilkan container yang running. Untuk melihat semuanya, tambahkan flag -a:

    docker ps -a

    Output:

    CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS                     PORTS                  NAMES
    7b2e4a1c9d03   nginx:1.27   "/docker-entrypoint.…"   5 minutes ago   Exited (0) 30 seconds ago                         webku2
    3f9c1d2e8b7a   nginx:1.27   "/docker-entrypoint.…"   8 minutes ago   Up 8 minutes               0.0.0.0:8080->80/tcp   webku

    Container Exited bisa dihidupkan lagi dengan docker start webku2, lengkap dengan isi writable layer-nya yang masih utuh. Kalau memang sudah tidak dibutuhkan, hapus permanen dengan:

    docker stop webku2
    docker rm webku2

    Ingat, docker rm hanya menghapus container. Image nginx:1.27 tetap ada di disk dan bisa dipakai membuat container baru kapan saja. Menghapus image adalah perintah lain, yaitu docker rmi, dan hanya bisa dilakukan kalau tidak ada container yang masih memakainya.

    Kenapa Container Langsung Exit? Kasus docker run ubuntu

    Ini kebingungan paling klasik. Coba jalankan:

    docker run -d --name coba-ubuntu ubuntu:24.04

    Lalu cek docker ps. Kosong, tidak ada coba-ubuntu. Cek docker ps -a, ternyata statusnya Exited (0) padahal baru saja dijalankan. Kenapa Nginx bertahan hidup tapi Ubuntu langsung mati?

    Aturannya satu: container hanya hidup selama proses utamanya hidup. Image nginx proses utamanya adalah web server yang memang dirancang berjalan terus menerus di foreground, menunggu request. Image ubuntu proses utamanya adalah bash. Karena container jalan di background tanpa terminal interaktif, bash tidak punya input apa pun, jadi dia langsung selesai. Bash selesai, container ikut exit. Ini bukan error, ini perilaku yang benar.

    Kalau mau masuk ke dalam Ubuntu dan main-main di shell-nya, jalankan dengan mode interaktif:

    docker run -it --name ubuntu-interaktif ubuntu:24.04 bash

    Flag -it memberi container terminal interaktif, jadi bash tetap hidup dan kamu langsung berada di dalam container. Prompt-mu berubah jadi seperti root@a1b2c3d4e5f6:/#. Ketik exit untuk keluar, dan begitu bash berhenti, container pun berstatus Exited. Konsisten dengan aturannya.

    Troubleshooting: Error yang Sering Dialami Pemula

    Error: port is already allocated

    docker: Error response from daemon: ... bind: address already in use

    Penyebab: port 8080 di komputermu sudah dipakai, entah oleh container lain atau aplikasi lain. Solusi: pakai port host lain, misalnya -p 8082:80, atau cari siapa yang memakai port itu dengan docker ps lalu stop container yang bentrok.

    Error: the container name is already in use

    docker: Error response from daemon: Conflict. The container name "/webku" is already in use

    Penyebab: nama container harus unik, dan container lama bernama sama masih ada meskipun statusnya Exited. Solusi: hapus dulu container lama dengan docker rm webku, atau pakai nama lain.

    Error: Cannot connect to the Docker daemon

    Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    Penyebab: dockerd tidak jalan, atau user-mu belum punya izin mengakses socket Docker. Solusi di Ubuntu: jalankan sudo systemctl start docker. Kalau masalahnya izin, pastikan user sudah masuk grup docker seperti dibahas di bagian 1, lalu logout dan login lagi. Di Windows, pastikan aplikasi Docker Desktop sedang berjalan.

    Container Nginx jalan tapi browser tidak bisa akses

    Penyebab paling umum: lupa flag -p saat docker run, jadi port container tidak tersambung ke host. Cek kolom PORTS di docker ps. Kalau kosong, hapus container itu dan jalankan ulang dengan -p 8080:80. Port mapping tidak bisa ditambahkan ke container yang sudah terlanjur dibuat.

    Rangkuman dan Lanjut ke Bagian 3

    Hari ini kamu sudah memegang konsep paling fundamental di Docker. Image itu cetakan yang read-only, container itu instance hidup yang dibuat dari cetakan tersebut, dan satu image bisa melahirkan banyak container yang saling independen. Kamu juga sudah tahu alur kerja client, daemon, dan registry, plus aturan emas bahwa container hanya hidup selama proses utamanya hidup.

    Pola kerja ini sama persis dengan yang dipakai di dunia kerja. Saat tim Arrazy membangun sistem aplikasi untuk klien, satu image backend yang sama bisa dijalankan sebagai container di laptop developer, di server staging, dan di server produksi tanpa ada cerita “di laptop saya jalan kok”.

    Bagian berikutnya, “Perintah Dasar Docker yang Wajib Dikuasai Pemula”, akan membedah perintah harian seperti docker ps, docker images, docker rm, dan kawan-kawannya secara sistematis. Artikelnya terbit menyusul, pantau daftarnya di halaman Belajar Docker dari Nol.

    Referensi

  • Apa Itu Docker dan Cara Install Docker di Ubuntu & Windows

    Apa Itu Docker dan Cara Install Docker di Ubuntu & Windows

    Docker adalah platform untuk mengemas aplikasi beserta semua dependensinya ke dalam satu paket yang disebut container. Container ini bisa jalan di mana saja dengan perilaku yang sama persis: di laptop kamu, di laptop teman satu tim, sampai di server produksi. Artikel ini adalah bagian pertama dari seri Belajar Docker dari Nol. Kita mulai dari dua hal paling dasar: paham kenapa Docker ada, lalu praktik cara install Docker di Ubuntu dan Windows sampai benar-benar bisa dipakai.

    Ringkasnya begini. Di Ubuntu, Docker Engine versi 27.x diinstall lewat repositori resmi apt dari download.docker.com. Di Windows, kamu install Docker Desktop yang berjalan di atas WSL2. Setelah terpasang, verifikasi dengan docker run hello-world. Detail tiap langkah kita bahas di bawah, termasuk error yang paling sering bikin pemula nyangkut.

    Masalah Klasik “Di Laptop Saya Jalan Kok”

    Hampir semua developer pernah mengalami ini. Aplikasi jalan mulus di laptop, begitu dideploy ke server langsung error. Penyebabnya macam-macam. Versi PHP di server beda dengan di laptop. Ekstensi yang dibutuhkan belum terpasang. Versi Node atau Go tidak sama. Library sistem yang di laptop ada, di server tidak ada.

    Cara deploy manual di VPS memperbesar peluang masalah ini. Alurnya biasanya begini: sewa VPS, SSH masuk, install runtime satu per satu, install database, atur konfigurasi, baru upload kode. Setiap langkah dikerjakan tangan, dan setiap server bisa berakhir dengan kondisi yang sedikit berbeda. Server seperti ini sering disebut snowflake server, tidak ada dua yang benar-benar identik. Saat aplikasi harus pindah server atau tim bertambah orang, proses setup harus diulang dari nol dan hasilnya belum tentu sama.

    Container lahir untuk memotong masalah itu. Aplikasi, runtime, library, dan konfigurasi dikemas jadi satu unit bernama image. Dari image itu kamu menjalankan container, dan container tersebut membawa lingkungannya sendiri ke mana pun dia jalan. Kalau container jalan di laptop, dia akan jalan dengan cara yang sama di server. Beda dengan virtual machine, container tidak membawa sistem operasi utuh. Container berbagi kernel dengan host, jadi ukurannya jauh lebih kecil dan startup-nya hitungan detik, bukan menit.

    Di tim Arrazy, hampir semua proyek klien berjalan di atas Docker, dari backend Go, aplikasi Laravel, sampai database di server klien. Alasannya sederhana: environment developer dan server produksi jadi seragam, dan onboarding anggota tim baru cukup dengan satu perintah, bukan setengah hari install dependensi. Pola yang sama juga kami pakai saat membangun sistem aplikasi untuk klien yang servernya kami kelola.

    Prasyarat: Nyaman di Terminal Dulu

    Seri ini banyak bermain di terminal. Kamu tidak perlu jago, tapi minimal paham perintah dasar seperti cd, ls, sudo, dan cara SSH ke server. Kalau bagian itu masih asing, selesaikan dulu bagian dasar shell dan SSH di seri Belajar Linux dari Nol, baru lanjut ke sini. Percaya deh, belajar Docker tanpa dasar terminal itu seperti belajar nyetir sambil belajar baca rambu.

    Kebutuhan sistemnya:

    • Ubuntu: versi 22.04 (Jammy) atau 24.04 (Noble), arsitektur 64-bit. VPS atau laptop sama saja.
    • Windows: Windows 10 64-bit versi 22H2 ke atas atau Windows 11, dengan fitur virtualisasi aktif di BIOS. RAM 8 GB sangat disarankan.

    Cara Install Docker di Ubuntu Lewat Repo Resmi apt

    Ubuntu punya paket docker.io di repo bawaan, tapi versinya sering tertinggal. Kita pakai repo resmi Docker supaya dapat Docker Engine 27.x yang terbaru beserta plugin Compose dan Buildx.

    1. Bersihkan Paket Lama dan Siapkan Dependensi

    Kalau sebelumnya pernah coba-coba install Docker dari repo bawaan, hapus dulu supaya tidak bentrok:

    for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

    Kalau paketnya memang tidak ada, apt hanya bilang paket tidak terpasang. Aman, lanjut saja. Lalu update index dan install alat bantu:

    sudo apt-get update
    sudo apt-get install ca-certificates curl

    2. Tambahkan GPG Key dan Repositori Docker

    GPG key dipakai apt untuk memastikan paket yang diunduh benar-benar dari Docker, bukan dari pihak lain:

    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc

    Lalu daftarkan repositorinya:

    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update

    Perintah di atas otomatis mendeteksi arsitektur dan kode nama Ubuntu kamu, jadi bisa dicopy apa adanya.

    3. Install Docker Engine dan Plugin-nya

    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    Lima paket itu isinya: daemon Docker (docker-ce), perintah docker di terminal (docker-ce-cli), runtime container (containerd.io), plus plugin build dan Compose yang akan kita pakai di bagian-bagian berikutnya seri ini. Setelah selesai, service Docker otomatis jalan. Cek versinya:

    docker --version

    Output yang diharapkan kurang lebih seperti ini:

    Docker version 27.5.1, build 9f9e405

    Angka minor dan build bisa beda tergantung rilis terbaru saat kamu install. Yang penting versi mayornya 27 ke atas.

    Cara Install Docker di Windows: Docker Desktop dan WSL2

    Docker butuh kernel Linux. Di Windows, kebutuhan itu dipenuhi lewat WSL2 (Windows Subsystem for Linux versi 2), lalu Docker Desktop jalan di atasnya. Urutannya: aktifkan WSL2 dulu, baru install Docker Desktop.

    1. Aktifkan WSL2

    Buka PowerShell sebagai Administrator (klik kanan, Run as administrator), lalu jalankan:

    wsl --install

    Perintah ini mengaktifkan fitur WSL, mengunduh kernel Linux, menjadikan WSL2 sebagai default, dan menginstall distro Ubuntu. Setelah selesai, restart komputer. Kalau WSL sudah pernah terpasang, pastikan versinya 2 dengan wsl --status dan update dengan wsl --update.

    2. Install Docker Desktop

    1. Unduh installer dari https://docs.docker.com/desktop/setup/install/windows-install/, pilih yang x86_64.
    2. Jalankan Docker Desktop Installer.exe. Saat muncul pilihan backend, pastikan opsi Use WSL 2 instead of Hyper-V tercentang.
    3. Selesaikan instalasi, logout atau restart bila diminta, lalu buka aplikasi Docker Desktop.

    Tunggu sampai indikator di pojok kiri bawah Docker Desktop berwarna hijau dengan status Engine running. Setelah itu semua perintah docker bisa kamu jalankan dari PowerShell maupun dari terminal Ubuntu di WSL. Sepanjang seri ini perintahnya sama persis untuk Ubuntu asli maupun WSL, jadi pengguna Windows tidak perlu artikel terpisah.

    Verifikasi Instalasi: docker version, docker info, hello-world

    Ada tiga pengecekan standar setelah install. Pertama, docker version (tanpa tanda strip). Bedanya dengan docker --version, perintah ini menampilkan versi client sekaligus server. Kalau bagian Server muncul, artinya daemon Docker hidup dan bisa diajak bicara:

    docker version
    Client: Docker Engine - Community
     Version:           27.5.1
     ...
    Server: Docker Engine - Community
     Engine:
      Version:          27.5.1
     ...

    Kedua, docker info untuk melihat kondisi keseluruhan: jumlah container, jumlah image, storage driver, dan lainnya. Untuk instalasi baru, nilai Containers dan Images masih 0.

    Ketiga, tes paling memuaskan: jalankan container pertamamu.

    docker run hello-world

    Output yang diharapkan:

    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    e6590344b1a5: Pull complete
    Digest: sha256:...
    Status: Downloaded newer image for hello-world:latest
    
    Hello from Docker!
    This message shows that your installation appears to be working correctly.

    Perhatikan alurnya, karena ini inti kerja Docker: image hello-world tidak ada di lokal, jadi Docker mengunduhnya dari Docker Hub, membuat container dari image itu, menjalankannya, lalu container mencetak pesan dan berhenti. Konsep image dan container ini kita bedah tuntas di bagian 2.

    Jalankan Docker Tanpa sudo: usermod -aG docker

    Di Ubuntu, daemon Docker jalan sebagai root dan socket-nya hanya bisa diakses root serta anggota grup docker. Karena itu, secara default setiap perintah harus diawali sudo. Capek kalau tiap perintah begitu. Solusinya, masukkan user kamu ke grup docker:

    sudo usermod -aG docker $USER

    Keanggotaan grup baru terbaca setelah kamu logout dan login lagi. Kalau tidak mau logout, jalankan newgrp docker untuk membuka shell baru dengan grup yang sudah aktif. Tes tanpa sudo:

    docker run hello-world

    Kalau pesan Hello from Docker muncul tanpa error, beres. Satu catatan penting: anggota grup docker pada praktiknya setara root di mesin itu, karena bisa me-mount filesystem host lewat container. Di laptop pribadi ini bukan masalah. Di server produksi yang dipakai banyak orang, pikirkan dulu siapa saja yang dimasukkan ke grup ini. Pengguna Docker Desktop di Windows tidak perlu langkah ini sama sekali.

    Troubleshooting: Error yang Sering Muncul Saat Install Docker

    permission denied while trying to connect to /var/run/docker.sock

    Pesan lengkapnya kurang lebih: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock. Penyebabnya user kamu belum masuk grup docker, atau sudah dimasukkan tapi belum logout-login. Solusi: jalankan sudo usermod -aG docker $USER, lalu logout dan login lagi. Cek dengan perintah groups, pastikan kata docker muncul di daftarnya.

    WSL2 Belum Aktif: “Docker Desktop requires a newer WSL kernel”

    Docker Desktop menolak jalan dan menyuruh update WSL. Ini terjadi karena WSL belum terpasang, masih versi 1, atau kernelnya usang. Buka PowerShell sebagai Administrator lalu jalankan wsl --update dan wsl --set-default-version 2, kemudian restart Docker Desktop. Kalau masih gagal, cek apakah virtualisasi aktif: buka Task Manager, tab Performance, lihat baris Virtualization. Kalau statusnya Disabled, aktifkan Intel VT-x atau AMD-V dari BIOS/UEFI.

    Unable to locate package docker-ce

    Muncul saat apt-get install docker-ce di Ubuntu. Artinya repositori Docker belum benar-benar terdaftar. Biasanya karena lupa menjalankan sudo apt-get update setelah menambah repo, atau file /etc/apt/sources.list.d/docker.list isinya salah karena perintah echo tadi tidak tercopy utuh. Cek isi file itu dengan cat, pastikan ada satu baris berisi kode nama Ubuntu kamu (misalnya noble), lalu ulangi sudo apt-get update.

    Cannot connect to the Docker daemon. Is the docker daemon running?

    Perintah docker jalan tapi daemon-nya mati. Di Ubuntu, nyalakan dengan sudo systemctl start docker dan supaya otomatis hidup saat boot jalankan sudo systemctl enable docker. Di Windows, error ini biasanya berarti aplikasi Docker Desktop belum dibuka. Buka dulu, tunggu status Engine running, baru jalankan perintah dari terminal.

    Sudah Terinstall, Selanjutnya Apa

    Sampai sini kamu sudah paham masalah yang diselesaikan container, punya Docker Engine 27.x yang jalan di Ubuntu atau Docker Desktop di Windows, dan sudah menjalankan container pertama tanpa sudo. Fondasi selesai.

    Di bagian 2, “Perbedaan Docker Image dan Container + Praktik Pertama”, kita bongkar konsep paling penting di Docker: apa itu image, apa itu container, dan kenapa keduanya sering tertukar di kepala pemula. Artikelnya terbit menyusul, pantau daftarnya di halaman hub Belajar Docker dari Nol.

    Referensi