Docker di Ubuntu: Panduan Lengkap Instalasi dan Penggunaan
Docker adalah platform kontainerisasi open-source yang mengemas aplikasi dan dependensinya ke dalam unit terisolasi dan portabel yang disebut container. Tidak seperti mesin virtual, container berbagi kernel OS host, sehingga jauh lebih ringan, lebih cepat untuk dijalankan, dan lebih efisien dalam penggunaan sumber daya — perbedaan penting bagi siapa pun yang menjalankan beban kerja di lingkungan VPS Hosting di mana sumber daya komputasi secara langsung memengaruhi biaya dan performa.
Panduan ini mencakup proses instalasi Docker secara lengkap di Ubuntu 20.04, 22.04, dan 24.04 LTS, termasuk penguatan pasca-instalasi, alur kerja Docker Compose, dan pola perintah yang relevan untuk produksi yang sering diabaikan oleh sebagian besar tutorial.
Prasyarat dan Persyaratan Sistem
Sebelum menjalankan satu perintah pun, verifikasi hal-hal berikut:
- Versi Ubuntu: 20.04 LTS (Focal), 22.04 LTS (Jammy), atau 24.04 LTS (Noble). Perintah `lsb_release -cs` yang digunakan saat pengaturan repositori akan secara otomatis mendeteksi nama kode Anda.
- Arsitektur: `amd64`, `arm64`, atau `armhf` semuanya didukung oleh repositori resmi Docker.
- Versi kernel: Docker memerlukan kernel Linux 3.10 atau lebih tinggi. Jalankan `uname -r` untuk memastikannya.
- Hak akses pengguna: `sudo` atau akses root wajib diperlukan untuk instalasi dan manajemen daemon.
- Ruang disk: Minimal 2 GB ruang kosong pada partisi yang menampung `/var/lib/docker`, yaitu tempat Docker menyimpan image, container, volume, dan cache build. Pada sistem produksi, pasang direktori ini pada partisi atau volume khusus.
Langkah pra-instalasi penting: Jika sebelumnya Anda menginstal Docker dari repositori `apt` default Ubuntu (paket `docker.io`), hapus terlebih dahulu untuk menghindari konflik dengan paket Docker CE resmi:
“`bash
sudo apt remove docker docker-engine docker.io containerd runc
“`
Langkah 1: Perbarui Paket Sistem
Perbarui indeks paket dan paket yang terinstal ke versi terbaru sebelum menambahkan repositori baru:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Ini memastikan bahwa resolver dependensi `apt` bekerja berdasarkan metadata paket terkini dan bahwa pustaka sistem dasar Anda tidak ketinggalan zaman — sumber umum dari kesalahan runtime yang tidak kentara pada aplikasi yang dikontainerisasi.
Langkah 2: Instal Docker Engine dari Repositori Resmi
Repositori `apt` default Ubuntu menyertakan paket bernama `docker.io`, yang dikelola oleh Canonical dan biasanya tertinggal beberapa versi dari rilis resmi Docker. Untuk penggunaan produksi, selalu instal dari repositori Docker sendiri.
2.1 Instal Dependensi Transport dan Verifikasi
“`bash
sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y
“`
Mengapa `gnupg`? Mulai Ubuntu 22.04, `gpg` tidak selalu tersedia secara default. Menyertakannya secara eksplisit mencegah impor kunci GPG gagal secara diam-diam.
2.2 Tambahkan Kunci GPG Resmi Docker
“`bash
sudo install -m 0755 -d /usr/share/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
“`
Langkah `chmod a+r` sering dilewati dalam tutorial tetapi diperlukan pada sistem di mana `apt` berjalan dalam konteks pengguna yang dibatasi — tanpanya, manajer paket tidak dapat membaca keyring dan akan menampilkan kesalahan `NO_PUBKEY` saat `apt update`.
2.3 Tambahkan Repositori Stabil Docker
“`bash
echo
"deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" |
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
“`
Substitusi `arch=$(dpkg –print-architecture)` sangat penting pada server berbasis ARM. Melakukan hardcode `amd64` di sini adalah kesalahan umum yang menyebabkan kegagalan resolusi paket secara diam-diam pada instans ARM.
2.4 Instal Docker Engine, CLI, dan Plugin
“`bash
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
“`
Rincian paket:
| Paket | Peran |
|---|
| — | — |
|---|
| `docker-ce` | Daemon Docker Engine (`dockerd`) |
|---|
| `docker-ce-cli` | CLI klien (perintah `docker`) |
|---|
| `containerd.io` | Runtime container tingkat rendah (sesuai OCI) |
|---|
| `docker-buildx-plugin` | Kemampuan build yang diperluas (multi-platform, BuildKit) |
|---|
| `docker-compose-plugin` | Compose V2 terintegrasi sebagai plugin CLI Docker |
|---|
Catatan tentang `containerd.io`: Ini tidak sama dengan paket `containerd` di repositori default Ubuntu. `containerd.io` Docker adalah versi runtime containerd yang spesifik dan telah diuji. Mencampurkan keduanya adalah sumber kegagalan startup daemon yang sudah diketahui.
Langkah 3: Verifikasi Instalasi
Konfirmasi bahwa daemon aktif dan diaktifkan untuk mulai saat boot:
“`bash
sudo systemctl status docker
sudo systemctl enable docker
“`
Periksa versi yang terinstal:
“`bash
sudo docker –version
sudo docker info
“`
`docker info` lebih informatif daripada `–version` saja — ini mengungkapkan driver penyimpanan yang digunakan (biasanya `overlay2`), driver cgroup (`systemd` vs `cgroupfs`), serta jumlah CPU dan memori yang dapat diakses Docker.
Jalankan uji asap standar:
“`bash
sudo docker run hello-world
“`
Eksekusi yang berhasil akan mencetak pesan “Hello from Docker!” dan mengonfirmasi bahwa daemon Docker, penarikan image dari Docker Hub, dan eksekusi container semuanya berfungsi dengan benar.
Langkah 4: Konfigurasi Docker untuk Akses Non-Root
Secara default, socket Docker (`/var/run/docker.sock`) dimiliki oleh `root` dan grup `docker`. Pengguna mana pun yang tidak berada dalam grup `docker` harus menggunakan `sudo` untuk setiap perintah Docker.
“`bash
sudo usermod -aG docker $USER
“`
Terapkan keanggotaan grup tanpa keluar dari sesi:
“`bash
newgrp docker
“`
Verifikasi:
“`bash
docker run hello-world
“`
Peringatan keamanan: Keanggotaan dalam grup `docker` secara efektif setara dengan `sudo` tanpa kata sandi. Pengguna dalam grup `docker` dapat dengan mudah memasang filesystem host ke dalam container dan melewati semua kontrol akses tingkat filesystem. Pada sistem multi-tenant atau server bersama, pertimbangkan untuk menggunakan rootless Docker sebagai gantinya:
“`bash
dockerd-rootless-setuptool.sh install
“`
Mode rootless menjalankan daemon Docker dan container di bawah namespace pengguna yang tidak memiliki hak istimewa, sehingga secara dramatis mengurangi permukaan serangan. Ini adalah konfigurasi yang direkomendasikan untuk lingkungan apa pun di mana beberapa pengguna berbagi host yang sama.
Langkah 5: Referensi Perintah Docker Penting
Manajemen Image
“`bash
Pull a specific image version from Docker Hub
docker pull nginx:1.27-alpine
List locally cached images
docker images
Remove a specific image
docker rmi nginx:1.27-alpine
Remove all dangling (untagged) images to reclaim disk space
docker image prune
Remove all unused images (not just dangling)
docker image prune -a
“`
Tips produksi: Selalu tarik tag berversi (misalnya, `nginx:1.27-alpine`) daripada `latest` dalam alur kerja otomatis atau produksi apa pun. Tag `latest` bersifat mutable — tag ini dapat menunjuk ke image yang berbeda setelah push ke registry, sehingga merusak reprodusibilitas.
Siklus Hidup Container
“`bash
Run a container interactively with a pseudo-TTY
docker run -it ubuntu:22.04 /bin/bash
Run a container in detached mode with port mapping and a name
docker run -d -p 8080:80 –name my-nginx nginx:1.27-alpine
List running containers
docker ps
List all containers (including stopped)
docker ps -a
Stop a running container gracefully (SIGTERM, then SIGKILL after timeout)
docker stop my-nginx
Start a stopped container
docker start my-nginx
Remove a stopped container
docker rm my-nginx
Force-remove a running container (sends SIGKILL immediately)
docker rm -f my-nginx
View real-time logs
docker logs -f my-nginx
Execute a command inside a running container
docker exec -it my-nginx /bin/sh
“`
Inspeksi Sumber Daya dan Sistem
“`bash
Display real-time resource usage statistics
docker stats
Inspect detailed container metadata (JSON)
docker inspect my-nginx
Display disk usage by Docker objects
docker system df
Remove all stopped containers, unused networks, dangling images, and build cache
docker system prune
“`
`docker system prune` adalah salah satu perintah pemeliharaan terpenting untuk server yang berjalan lama. Tanpa pembersihan berkala, cache build Docker dan container yang dihentikan dapat mengonsumsi puluhan gigabyte pada host pengembangan atau CI yang aktif.
Langkah 6: Docker Compose — Orkestrasi Aplikasi Multi-Container
Docker Compose V2 (`docker-compose-plugin` yang diinstal sebelumnya) dipanggil sebagai `docker compose` (dengan spasi), bukan `docker-compose` warisan (dengan tanda hubung). Kedua sintaks berfungsi jika Anda memiliki plugin yang terinstal, tetapi V2 adalah standar saat ini.
6.1 Memahami Struktur File Compose
Buat direktori proyek dan file `compose.yml` (nama file yang disukai di Compose V2; `docker-compose.yml` tetap didukung untuk kompatibilitas mundur):
“`bash
mkdir ~/my-web-app && cd ~/my-web-app
nano compose.yml
“`
Contoh realistis untuk produksi dengan Nginx dan layanan backend:
“`yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
depends_on:
- app
restart: unless-stopped
app:
image: node:20-alpine
working_dir: /usr/src/app
volumes:
- ./app:/usr/src/app
command: node server.js
environment:
- NODE_ENV=production
restart: unless-stopped
“`
Penjelasan direktif Compose utama:
- `restart: unless-stopped` — Container akan restart secara otomatis setelah crash atau reboot sistem, kecuali dihentikan secara eksplisit oleh operator. Ini adalah kebijakan yang tepat untuk layanan yang berjalan lama; `always` akan restart bahkan container yang sengaja dihentikan.
- `depends_on` — Mengontrol urutan startup tetapi tidak menunggu layanan *siap* (misalnya, database yang menerima koneksi). Untuk gating kesiapan, gunakan `healthcheck` dikombinasikan dengan `condition: service_healthy`.
- `volumes` dengan `:ro` — Memasang file konfigurasi sebagai read-only mencegah proses container yang terkompromi memodifikasi konfigurasinya sendiri.
6.2 Perintah Alur Kerja Compose
“`bash
Start all services in detached mode
docker compose up -d
View logs for all services
docker compose logs -f
View logs for a specific service
docker compose logs -f web
List running Compose services
docker compose ps
Scale a specific service to multiple replicas
docker compose up -d –scale app=3
Stop services without removing containers
docker compose stop
Stop and remove containers, networks, and volumes
docker compose down –volumes
Rebuild images before starting (useful after code changes)
docker compose up -d –build
“`
6.3 Verifikasi Layanan yang Berjalan
“`bash
curl -I http://localhost:8080
“`
Respons `200 OK` mengonfirmasi bahwa Nginx berfungsi dengan benar. Untuk layanan yang berjalan di instans VPS Hosting jarak jauh, ganti `localhost` dengan alamat IP publik server Anda dan pastikan port yang relevan terbuka di firewall Anda (`ufw allow 8080/tcp`).
Langkah 7: Dasar-Dasar Jaringan Docker
Memahami model jaringan Docker sangat penting untuk membangun aplikasi multi-container yang berkomunikasi dengan aman.
Driver jaringan default:
| Driver | Kasus Penggunaan |
|---|
| — | — |
|---|
| `bridge` | Default untuk container mandiri; namespace jaringan terisolasi pada host |
|---|
| `host` | Container berbagi stack jaringan host; performa maksimum, tanpa isolasi |
|---|
| `none` | Tanpa akses jaringan; berguna untuk pemrosesan batch atau beban kerja yang sensitif terhadap keamanan |
|---|
| `overlay` | Jaringan multi-host untuk cluster Docker Swarm |
|---|
| `macvlan` | Menetapkan alamat MAC ke container; muncul sebagai perangkat fisik di jaringan |
|---|
Membuat dan menggunakan jaringan bridge kustom:
“`bash
Create an isolated network
docker network create my-app-network
Run containers attached to the custom network
docker run -d –name db –network my-app-network postgres:16-alpine
docker run -d –name api –network my-app-network my-api-image
Containers on the same custom bridge network can resolve each other by name
Inside 'api', you can connect to 'db' using the hostname 'db'
“`
Jaringan bridge kustom menyediakan resolusi DNS otomatis antar container berdasarkan nama container. Jaringan `bridge` default tidak menyediakan hal ini — ini adalah perbedaan penting yang menyebabkan kegagalan koneksi ketika pengembang mengasumsikan container pada jaringan default dapat saling menjangkau berdasarkan nama.
Langkah 8: Data Persisten dengan Volume Docker
Container bersifat sementara secara desain. Setiap data yang ditulis di dalam filesystem container akan hilang ketika container dihapus. Untuk penyimpanan persisten, gunakan volume atau bind mount.
“`bash
Create a named volume
docker volume create pgdata
Use the volume with a container
docker run -d
–name postgres-db
-e POSTGRES_PASSWORD=securepassword
-v pgdata:/var/lib/postgresql/data
postgres:16-alpine
List volumes
docker volume ls
Inspect a volume (shows mount point on host)
docker volume inspect pgdata
Remove unused volumes
docker volume prune
“`
Volume vs. bind mount:
| Fitur | Named Volume | Bind Mount |
|---|
| — | — | — |
|---|
| Dikelola oleh Docker | Ya | Tidak |
|---|
| Memerlukan path host | Tidak | Ya |
|---|
| Portabel antar host | Ya (dengan driver volume) | Tidak |
|---|
| Terbaik untuk | Data database, status aplikasi | Kode pengembangan, file konfigurasi |
|---|
| Mekanisme backup | `docker run –volumes-from` | Alat filesystem standar |
|---|
Langkah 9: Menjaga Docker Tetap Diperbarui
Repositori resmi Docker menangani pembaruan melalui mekanisme `apt` standar:
“`bash
sudo apt update
sudo apt upgrade -y
“`
Untuk memperbarui hanya paket terkait Docker tanpa memutakhirkan seluruh sistem:
“`bash
sudo apt install –only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
“`
Periksa catatan rilis Docker sebelum pemutakhiran versi mayor, terutama untuk perubahan pada driver penyimpanan, penanganan versi cgroup, atau versi API yang sudah tidak digunakan lagi yang dapat memengaruhi file `compose.yml` yang sudah ada.
Docker vs. Pendekatan Kontainerisasi Alternatif
| Fitur | Docker Engine | Podman | LXC/LXD | containerd (mandiri) |
|---|
| — | — | — | — | — |
|---|
| Arsitektur daemon | Daemon terpusat | Tanpa daemon | Berbasis daemon | Berbasis daemon |
|---|
| Dukungan rootless | Ya (v20+) | Native | Terbatas | Ya |
|---|
| Dukungan Docker Compose | Native | Melalui `podman-compose` | Tidak | Tidak |
|---|
| Kepatuhan OCI | Ya | Ya | Tidak (format LXC) | Ya |
|---|
| Integrasi Kubernetes | Melalui shim CRI-dockerd | CRI native | Tidak | CRI native |
|---|
| Dukungan Windows/macOS | Docker Desktop | Terbatas | Tidak | Tidak |
|---|
| Paling cocok untuk | Pengembangan umum dan produksi | Berfokus pada keamanan, rootless | Container sistem, VM | Node Kubernetes |
|---|
Untuk tim yang menjalankan beban kerja terkontainerisasi dalam skala besar pada bare metal, lingkungan Dedicated Servers memberi Anda kendali penuh atas parameter kernel, penjadwalan I/O penyimpanan, dan konfigurasi jaringan — yang semuanya secara langsung memengaruhi kepadatan container dan performa.
Daftar Periksa Penguatan Produksi
Sebelum menjalankan Docker di lingkungan produksi, tangani hal-hal berikut:
Konfigurasi daemon (`/etc/docker/daemon.json`):
“`json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"userns-remap": "default",
"live-restore": true,
"no-new-privileges": true
}
“`
- `log-opts` dengan `max-size` dan `max-file`: Tanpa rotasi log, file log JSON Docker akan memenuhi disk Anda. Ini adalah salah satu penyebab paling umum dari pemadaman server yang tidak terduga pada host yang dikontainerisasi.
- `userns-remap: "default"`: Mengaktifkan remapping namespace pengguna, sehingga root container (UID 0) dipetakan ke UID yang tidak memiliki hak istimewa pada host.
- `live-restore: true`: Memungkinkan container tetap berjalan jika daemon Docker crash atau dimulai ulang selama pemutakhiran — penting untuk pemeliharaan tanpa downtime.
- `no-new-privileges: true`: Mencegah proses container mendapatkan hak istimewa tambahan melalui biner `setuid` atau `setgid`.
Pertimbangan jaringan dan firewall:
Docker memanipulasi `iptables` secara langsung dan melewati aturan `ufw` secara default. Container dengan port yang dipublikasikan (`-p 8080:80`) akan dapat diakses dari internet meskipun `ufw deny 8080` telah diatur. Untuk menerapkan aturan `ufw` atas manipulasi `iptables` Docker, tambahkan `"iptables": false` ke `daemon.json` dan kelola routing secara manual, atau gunakan `–network host` Docker dengan aturan `ufw` yang eksplisit.
Untuk proyek yang memerlukan terminasi HTTPS, padukan aplikasi yang dikontainerisasi dengan reverse proxy yang dikonfigurasi dengan benar (Nginx atau Traefik) dan sertifikat yang valid. SSL Certificates adalah prasyarat untuk layanan web produksi apa pun yang berjalan di balik stack yang dikontainerisasi.
Jika beban kerja Anda melibatkan inferensi machine learning, penyajian model, atau pemrosesan data yang dipercepat GPU di dalam container, NVIDIA Container Toolkit terintegrasi langsung dengan Docker Engine. GPU Hosting menyediakan perangkat keras yang mendasari yang diperlukan untuk beban kerja ini.
Untuk tim yang mengelola beberapa proyek dengan manajemen container berbasis web, VPS with cPanel menawarkan lingkungan panel kontrol terkelola yang dapat melengkapi deployment berbasis Docker untuk stack aplikasi yang lebih sederhana.
Poin Teknis Utama dan Matriks Keputusan
Kapan menggunakan Docker di VPS vs. server dedicated:
- Gunakan VPS untuk lingkungan pengembangan, staging, dan beban kerja produksi dengan lalu lintas rendah hingga menengah di mana kepadatan container adalah 10–50 container.
- Gunakan server dedicated ketika kepadatan container melebihi 50 instans, ketika Anda membutuhkan performa I/O yang dapat diprediksi (tanpa efek noisy-neighbor), atau ketika penyetelan parameter kernel (`sysctl`) diperlukan untuk beban kerja Anda.
Daftar periksa operasional sebelum go live:
- Konfigurasi rotasi log di `daemon.json` (`max-size`, `max-file`)
- Aktifkan `live-restore` untuk bertahan dari restart daemon tanpa downtime container
- Gunakan named volume, bukan bind mount, untuk data layanan stateful
- Sematkan versi image di semua file `compose.yml` — jangan pernah gunakan `latest` di produksi
- Aktifkan `userns-remap` atau jalankan rootless Docker pada host multi-tenant
- Audit aturan `iptables` setelah instalasi Docker untuk memastikan kebijakan firewall tidak dilewati
- Atur `restart: unless-stopped` pada semua layanan yang berjalan lama
- Jalankan `docker system prune` pada cron job terjadwal untuk mencegah kehabisan disk
- Gunakan jaringan bridge kustom untuk semua komunikasi antar container — jangan pernah mengandalkan bridge default untuk penemuan layanan
FAQ
Apakah Docker di Ubuntu menggunakan `systemd` atau `cgroupfs` sebagai driver cgroup secara default?
Sejak Docker Engine 20.10, driver cgroup default pada sistem berbasis `systemd` (termasuk semua rilis Ubuntu LTS modern) adalah `systemd`. Ini selaras dengan persyaratan Kubernetes dan menghindari ketidakstabilan yang disebabkan oleh menjalankan dua manajer cgroup secara bersamaan. Anda dapat memverifikasinya dengan `docker info | grep -i cgroup`.
Apa perbedaan antara `docker compose down` dan `docker compose stop`?
`docker compose stop` menghentikan container yang berjalan tetapi mempertahankannya beserta jaringan yang terkait. `docker compose down` menghentikan container dan kemudian menghapusnya beserta jaringan yang dibuat oleh Compose. Menambahkan `–volumes` ke `down` juga menghapus named volume yang didefinisikan dalam file Compose — gunakan flag ini dengan hati-hati di produksi, karena akan menghapus data persisten secara permanen.
Mengapa Docker melewati aturan firewall `ufw` di Ubuntu?
Docker menyisipkan aturan `iptables`-nya sendiri di chain `DOCKER` dan `DOCKER-USER`, yang dievaluasi sebelum aturan chain `INPUT` milik `ufw`. Ini berarti port yang dipublikasikan dengan `-p` dapat dijangkau dari internet terlepas dari kebijakan `ufw`. Mitigasi yang tepat adalah menambahkan aturan langsung ke chain `DOCKER-USER`, atau mengikat port yang dipublikasikan ke antarmuka tertentu (misalnya, `-p 127.0.0.1:8080:80`) ketika akses eksternal tidak diperlukan.
Bagaimana cara membatasi CPU dan memori yang dapat dikonsumsi oleh container Docker?
Gunakan flag pembatas sumber daya saat runtime: `docker run –memory="512m" –cpus="1.5" my-image`. Di Compose, atur ini di bawah kunci `deploy.resources` (Compose V2) atau kunci tingkat atas `mem_limit` dan `cpus`. Tanpa batasan, satu container yang tidak terkendali dapat menghabiskan sumber daya host dan menjatuhkan semua container lain pada host yang sama.
Bisakah saya menjalankan Docker di dalam container Docker (Docker-in-Docker)?
Ya, tetapi sangat tidak disarankan untuk penggunaan produksi. Pola umum untuk pipeline CI adalah memasang socket Docker host (`-v /var/run/docker.sock:/var/run/docker.sock`) ke dalam container CI, yang memberi container kendali penuh atas daemon Docker host — risiko keamanan yang signifikan. Alternatif yang lebih aman adalah menggunakan flag `–allow security.insecure` BuildKit atau alat yang dibuat khusus seperti Kaniko atau Buildah, yang membangun image OCI tanpa memerlukan daemon Docker.
