Memahami Docker dari Dasar

Pengenalan Docker dari konsep dasar hingga penggunaan Docker yang efektif


Docker Header

Introduction

Pada blog kali ini, ada beberapa hal yang perlu dipahami terlebih dahulu agar nantinya anda dapat lebih mudah untuk memahami Docker. Hal-hal tersebut meliputi dasar-dasar sistem operasi, pengunaan perintah di terminal/command line dan pemahaman dasart tentang virtual machine.

Kita tidak hanya akan membahas perintah-perintah dasar Docker, tetapi kita juga akan membahas konsep dasar Docker. Harapannya, setelah membaca blog ini, pembaca dapat memahami bagaimana Docker bekerja dan bagaimana cara menggunakannya dengan efektif.

Pengenalan Container

Sebelum membahas Docker lebih lanjut, kita perlu berkenalan dengan Container terlebih dahulu. Container merupakah salah satu teknologi yang memungkinkan aplikasi berjalan dalam lingkungan yang terisolasi.

Lingkungan yang terisolasi ini penting karena memungkinkan aplikasi berjalan tanpa terpengaruh oleh aplikasi lain yang berjalan dalam lingkungan yang sama. Misalnya, jika di dalam satu mesin/lingkungan yang sama terdapat sebuah proses yang gagal, maka proses tersebut tidak akan mempengaruhi proses lain yang berjalan dalam lingkungan yang sama.

Selain menggunakan Container, ada cara lain untuk menciptakan lingkungan yang terisolasi, yaitu dengan menggunakan Virtual Machine, yang akan dibahas pada bagian berikutnya.

Virtual Machine

Virtual Machine (VM) adalah sistem komputer yang berjalan secara virtual di atas perangkat keras fisik dengan bantuan hypervisor atau virtual machine monitor. VM memungkinkan kita untuk menjalankan beberapa sistem operasi dalam satu mesin fisik.

VM memiliki kelebihan dan kekurangan masing-masing. Kelebihan VM adalah memungkinkan kita untuk menjalankan beberapa sistem operasi dalam satu mesin fisik. Namun, VM memiliki kekurangan, yaitu membutuhkan resource yang cukup besar. Hal ini dikarenakan setiap VM memiliki sistem operasi yang berbeda, sehingga membutuhkan resource yang cukup besar.

VM Ilustration https://www.docker.com/resources/what-container/

Seperti yang terlihat pada ilustrasi diatas, setiap VM berjalan dengan sistem operasinya sendiri di atas hypervisor (ex: VMware dan VirtualBox). Hal ini menyebabkan VM membutuhkan resource yang cukup besar. Selain itu, VM juga membutuhkan waktu yang cukup lama untuk diinstal dan dijalankan.

Container

Berbeda dengan VM, Container berjalan di atas host OS dan menggunakan kernel yang sama dengan host OS. Container memungkinkan kita untuk menjalankan aplikasi dalam lingkungan yang terisolasi tanpa perlu menginstal sistem operasi yang berbeda. Hal ini membuat Container lebih ringan dan lebih cepat dibandingkan dengan VM.

Dengan Container yang berfokus pada sisi apliaksi, kita bisa mem-package aplikasi dan dependency-nya tanpa harus menggabungkan sistem operasi. Hal ini membuat Container lebih efisien dan lebih mudah untuk di-deploy. Ukuran Container biasanya hanya hitungan MB, berbeda dengan VM yang bisa mencapai GB karena didalamnya terdapat sistem operasi.

Container Ilustration https://www.docker.com/resources/what-container/

Dapat dilihat dari ilustrasi di atas, Container berjalan di atas host OS dan menggunakan kernel yang sama dengan host OS. Container ini akan diatur oleh Container Engine seperti Docker, Containerd, dan Podman. Meskipun berjalan di atas host OS, Container tetap terisolasi dan tidak akan memengaruhi sistem operasi host.

Pengenalan Docker

Docker adalah salah satu Container Engine/Manager yang paling populer saat ini. Docker memungkinkan kita untuk membuat, mengelola, dan menjalankan Container dengan mudah. Docker juga menyediakan berbagai fitur yang memudahkan kita untuk mengelola Container, seperti Dockerfile, Docker Compose, dan Docker Swarm.

Arsitektur Docker

Docker menggunakan arsitektur client-server, dimana Docker client berkomunikasi dengan Docker daemon (server) melalui REST API. Saat menginstall Docker, biasanya sudah termasuk Docker Client dan Docker Daemon.

Docker terdiri dari beberapa komponen, yaitu: Docker Daemon, Docker Client, Docker Image, Docker Container, dan Docker Registry.

Docker Architecture https://docs.docker.com/get-started/docker-overview/

Seperti yang terlihat pada ilustrasi di atas, Arsitektur Docker terdiri dari beberapa komponen utama, yaitu Docker Client, Docker Daemon, Docker Image, Docker Container, dan Docker Registry. Komponen-komponen tersebut akan dibahas lebih lanjut pada bagian selanjutnya.

Menginstall Docker

Dalam blog ini, kita tidak akan membahas cara instalasi Docker secara mendetail, karena sudah banyak tutorial yang tersedia. Namun, berikut adalah panduan singkat bagi pembaca sesuai dengan sistem operasi yang digunakan:

  • Windows & macOS → Gunakan Docker Desktop dengan mengikuti panduan resmi di Docker Docs.
  • Linux → Gunakan Docker Engine dengan mengikuti instruksi di Docker Docs.

Apa perbedaan dari Docker Desktop dan Docker Engine? pada dasarnya Docker berjalan di atas OS Linux sehingga, jika kita menggunakan OS Windows atau MacOS, kita perlu menggunakan Docker Desktop yang sudah menggunakan virtualisasi (Hyper-V, WSL 2, etc) untuk menjalankan Docker Engine. Sedangkan, Docker Engine adalah versi Docker yang berjalan langsung di OS Linux tanpa GUI. Karena Docker Desktop menggunakan virtualisasi, konsumsi resource-nya lebih besar dibandingkan dengan Docker Engine yang berjalan secara native di Linux.

Docker Registry

Docker Registry adalah tempat penyimpanan Docker Image. Docker Registry memungkinkan kita untuk menyimpan, mengelola, dan mendistribusikan Docker Image. Docker Image itu sendiri akan di bahas pada bagian selanjutnya. Perumpamaan sederhananya, Docker Registry adalah tempat penyimpanan seperti GitHub untuk source code (Docker Image pada kasus ini).

Docker Architecture

Seperti yang terlihat pada ilustrasi di atas, Docker Registry menjadi tempat penyimpanan Docker Image. Docker Registry bisa berupa Docker Hub (public registry), Docker Trusted Registry (private registry), atau registry lain yang bisa kita deploy sendiri.

Docker Image

Docker Image adalah template yang digunakan untuk membuat Docker Container (akan bahas di bagian selanjutnya). Docker Image dapat diibaratkan seperti installer aplikasi, yang di dalamnya sudah terdapat aplikasi dan dependency yang diperlukan untuk menjalankannya.

Agar sebuah aplikasi dapat berjalan di Docker, kita perlu membuat atau memiliki Docker Image terlebih dahulu, agar nantinya kita dapat membuat Docker Container berdasarkan image tersebut. Docker Image bersifat read-only dan immutable, yang berarti setelah Image dibuat, isi di dalamnya tidak dapat diubah. Jika diperlukan perubahan, kita harus membuat Image baru berdasarkan Image sebelumnya.

Berikut merupakan beberapa perintah dasar untuk mengelola Docker Image:

# Melihat daftar Docker Image yang sudah di-download
docker images ls
 
# Mendownload Docker Image dari Docker Registery (cth: Docker Hub di https://hub.docker.com)
docker pull <image-name>:<tag>
 
# Menghapus Docker Image
docker image rm <image-name>:<tag>

Docker Container

Jika Docker Image seperti installer aplikasi, maka Docker Container adalah hasil aplikasi dari installernya. Seperti yang dijelaskan sebelumnya, Docker Image ini seperti installer ataupun template yang digunakan untuk membuat Docker Container. Sehingga kita dapat membuat beberapa Docker Container dari satu Docker Image (template) yang sama, asalkan dengan nama yang berbeda untuk hasil containernya.

Jika kita sudah membuat Docker Container, kita tidak dapat menghapus Image yang digunakan untuk membuat Container tersebut. Hal ini dikarenakan Docker Container ini menggunakan Image tersebut untuk berjalan, hal ini dikarenakan Docker Container tidak meng-copy isi Image tersebut, melainkan menggunakan isi Image tersebut.

Berikut merupakan beberapa perintah dasar untuk mengelola Docker Container, untuk perintah lebih lengkapnya dapat bisa dilihat pada Docker Docs:

# Melihat daftar Docker Container yang sedang berjalan
docker container ls
 
# Melihat semua daftar Docker Container baik yang sedang berjalan maupun yang tidak
docker container ls -a
 
# Membuat Docker Container dari Docker Image
docker create <image-name>:<tag> # docker create --name <container-name> <image-name>:<tag>
 
# Membuat Docker Container dari Docker Image dan menjalankannya
docker run <image-name>:<tag>
 
# Menjalan Docker Container yang sudah dibuat
docker start <container-name>
 
# Menghentikan Docker Container yang sedang berjalan
docker stop <container-name>
 
# Menghapus Docker Container
docker rm <container-name>

Container Log

Container Log adalah output yang dihasilkan oleh Docker Container. Log ini berisi informasi tentang kegiatan yang dilakukan oleh Container, seperti error, warning, info, dan lain-lain. Log ini sangat berguna untuk debugging dan monitoring aplikasi yang berjalan di dalam Container.

# Melihat log dari Docker Container
docker logs <container-name>
# Melihat log secara real-time
docker logs -f <container-name>

Container Exec

Container Exec atau docker exec adalah perintah yang digunakan untuk mengeksekusi perintah di dalam Docker Container yang sedang berjalan. Kita juga bisa menggunakan docker exec untuk seolah-olah masuk ke dalam Container tersebut dan menjalankan perintah di dalamnya. Berikut merupakan contoh penggunaan perintah docker exec:

# Mengeksekusi perintah di dalam Docker Container
docker exec <container-name> <command>
docker exec my-container ls -l # contoh
 
# Masuk ke dalam Docker Container
docker exec -it <container-name> /bin/bash # -i : interactive, -t : terminal

Container Port

Karena saat menjalankan container, container tersebut terisolasi di dalam Docker, maka host (laptop kita) tidak bisa langsung mengakses aplikasi yang berjalan di dalam container. Untuk mengakses aplikasi yang berjalan di dalam container, kita perlu meneruskan port (Port Forwarding) dari container tersebut ke host.

Port Forwarding ini bisa dilakukan dengan menggunakan perintah docker run atau docker create dengan menggunakan opsi -p atau --publish. Berikut merupakan contoh penggunaan perintah port forwarding:

# Menjalankan Docker Container dan meneruskan port
docker run -p <host-port>:<container-port> <image-name>:<tag>
docker run -p 8080:80 nginx # contoh
  • host-port adalah port yang akan diakses oleh host (laptop kita).
  • container-port adalah port yang digunakan oleh aplikasi yang berjalan di dalam container.

Container Environment Variabel

Container Environment Variabel adalah variabel yang digunakan oleh Docker Container untuk mengatur atau konfigurasi aplikasi yang berjalan di dalam Container. Variabel ini bisa digunakan untuk mengatur koneksi database, konfigurasi aplikasi, setting environment, dan lain-lain.

Berikut merupakan contoh penggunaan perintah untuk mengatur Environment Variabel pada Docker Container:

# Menjalankan Docker Container dengan Environment Variabel
docker run -e <key>=<value> <image-name>:<tag> # juga sama pada docker create
docker run -e DB_HOST=localhost -e DB
 
# Menjalankan Docker Container dengan Environment Variabel dari file
docker run --env-file <file> <image-name>:<tag>
docker run --env-file .env <image-name>:<tag>

Container Statistic

Container Statistic adalah informasi yang digunakan untuk monitoring dan mengukur performa dari Docker Container. Statistic ini berisi informasi tentang CPU, Memory, Network, Disk, dan lain-lain dari semua Container yang sedang berjalan.

Berikut merupakan contoh penggunaan perintah untuk melihat Container Statistic:

docker stats # menampilkan statistic dari semua container yang sedang berjalan
docker stats <container-name> # menampilkan statistic dari container tertentu

Container Resource Limit

Saat membuat container, secara default container akan menggunakan semua resoucre yang diberikan ke Docker (Windows dan Mac), dan untuk Linux akan menggunakan semua resource yang ada di mesin. Hal ini bisa menyebabkan container menghabiskan semua resource yang ada di mesin, sehingga bisa menyebabkan masalah pada container lain yang berjalan di mesin yang sama.

Oleh karena itu, kita perlu mengatur resource yang digunakan oleh container agar tidak menghabiskan semua resource yang ada di mesin. Untuk mengatur resource yang digunakan oleh container, kita bisa menggunakan perintah docker run dengan opsi --memory dan --cpus.

Berikut merupakan contoh penggunaan perintah untuk mengatur resource yang digunakan oleh container:

docker run --memory <value> --cpus <value> <image-name>:<tag>
# value untuk --memory bisa menggunakan m, g, k, b (megabyte, gigabyte, kilobyte, byte)
# value untuk --cpus bisa menggunakan desimal (0.5, 1.0, 1.5, dst) untuk Core CPU
docker run --memory 512m --cpus 0.5 <image-name>:<tag> # contoh

Bind Mount

Bind Mount adalah cara untuk menghubungkan (mounting) folder atau file di host (laptop kita) ke dalam Docker Container. Fitur ini sangat berguna ketika kita ingin mengirim konfigurasi dari luar container, ataupun menyimpan data yang dihasilkan oleh container ke host (luar container).

Berikut merupakan contoh penggunaan perintah untuk menggunakan Bind Mount:

docker run --mount type=bind,source=<host-path>,target=<container-path> <image-name>:<tag>
docker run --mount type=bind,source=<host-path>,target=<container-path>,readonly <image-name>:<tag>
  • type : Tipe mount, bisa berupa bind, volume, atau tmpfs.
  • source, src : Path dari file atau folder yang akan di-mount (host).
  • destination, dst, target : Path dari file atau folder yang akan di-mount ke dalam container (tergantung image-nya nyimpan datanya dimana).
  • readonly : Opsi untuk membuat mount menjadi read-only.

Docker Volume

Fitur Bind Mounts sudah ada sejak Docker versi awal, namun diversi terbaru kita direkomendasikan menggunakan Docker Volume. Docker Volume mirip dengan Bind Mounts, yang membedakannya adalah terdapat management Volume yang mempermudah kita untuk membuat, melihat daftar dan menghapus Volume.

Sederhananya, Docker Volume adalah storage yang digunakan oleh Docker Container untuk menyimpan data, bedanya dengan Bind Mounts, pada Bind Mounts data disimpan di host, sedangkan pada Docker Volume data tetap disimpan di dalam Docker namun terpisah dari Container sehingga data tersebut tidak akan hilang saat Container dihapus.

Berikut merupakan contoh penggunaan perintah untuk menggunakan Docker Volume:

# Melihat daftar Docker Volume
docker volume ls
 
# Membuat Docker Volume
docker volume create <volume-name>
 
# Menghapus Docker Volume
docker volume rm <volume-name>

Terdapat beberapa Image yang secara default menggunakan Docker Volume, seperti MySQL, PostgreSQL, dan MongoDB. Sehingga, ketika kita membuat Container dari Image tersebut, data akan disimpan di dalam Docker Volume agar data tersebut tidak hilang saat Container dihapus.

Container Volume

Volume yang sudah pernah kita buat, bisa kita gunakan kembali pada Container lain. Hal ini bisa dilakukan dengan menggunakan perintah docker run dengan opsi -v atau --mount.

Berikut merupakan contoh penggunaan perintah untuk menggunakan Docker Volume pada Container lain:

docker run -v <volume-name>:<container-path> <image-name>:<tag>
docker run --mount type=volume,source=<volume-name>,target=<container-path> <image-name>:<tag>

Backup Volume

Sayangnya, Docker tidak menyediakan perintah untuk melakukan backup Volume secara langsung. Namun, kita bisa memanfaatkan penggunaan Container dan Bind Mounts untuk melakukan backup Volume.

Berikut merupakan contoh konsep penggunaan perintah untuk melakukan backup Volume:

# Matikan container yang menggunakan Volume, agar data tidak berubah saat backup
docker stop <volume-container-name>
 
# Membuat Container baru untuk backup Volume
# dengan Bind Mount, source: host path, target: zip container path (path container yg udh di zip backup)
# dengan Bind Volume, source: volume name(yg mau di backup), target: save container path (path container buat nyimpen backup murni, blm zip)
docker run --name <backup-container-name>
--mount "type=bind,source=<host-path>,target=<zip-container-path>"
--mount "type=volume,source=<volume-name>,target=<save-container-path>"
<image-name>:<tag> # saran image: alpine, karena 1x eksekusi langsung mati imagenya
 
# Masuk ke dalam Container untuk melakukan backup, zip data lalu save bind mount ke host
docker exec -it <backup-container-name> /bin/bash
 
# Backup: nge-zip data dri volume ke path container yg nyambung ke host melalui bind mount
tar cvf <zip-container-path>/<backup-name>.tar <save-container-path>
 
# Selanjutnya, stop container, delete container, dan start container yang menggunakan volume-nya kembali
docker container stop <backup-container-name>
docker container rm <backup-container-name>
docker start <volume-container-name>

Kode di atas merupakan contoh konsep penggunaan perintah untuk melakukan backup Volume. Kita bisa menggabungkan beberapa perintah tersebut menjadi satu line agar lebih mudah digunakan.

docker run --rm --name <backup-container-name> --mount "type=volume,source=<volume-name>,target=<container-path>" --mount "type=bind,source=<host-path>,target=/backup" <image-name>:<tag> tar cvf /backup/<backup-name>.tar <container-path>
# Contoh penggunaan:
docker container stop <used-volume-container>
docker run --rm --name backup-container --mount "type=volume,source=<my-volume>,target=/data" --mount "type=bind,source=/backup,target=/backup" alpine:latest tar cvf /backup/my-volume.tar /data
docker container start <used-volume-container>

Restore Volume

Sama seperti backup, Docker tidak menyediakan perintah untuk melakukan restore Volume secara langsung. Namun, kita bisa memanfaatkan penggunaan Container dan Bind Mounts untuk melakukan restore Volume. Berikut merupakan contoh konsep penggunaan perintah untuk melakukan restore Volume:

docker volume create <my-volume-restore> # tempat save data dari restore-nya
docker run --rm --name restore-container --mount "type=volume,source=<my-volume-restore>,target=/data" --mount "type=bind,source=/backup,target=/backup" alpine:latest tar xvf /backup/my-volume.tar --strip 1

Konsepnya mirip dengan backup, pertama kita buat volume baru untuk menyimpan data yang akan di-restore. Selanjutnya, buat container yang menyambungkan host (tempat backup file berada) dengan Bind Mount ke container baru, dan sambungkan volume baru dengan container tersebut menggunakan Bind Volume. Terakhir, ekstrak file backup (yg sudah ada di container, yg di dapat dari Bind host), maka file tersebut akan tersimpan ke volume baru melalui Bind yang sudah dibuat sebelumnya.

Docker Network

Docker Network adalah fitur yang digunakan untuk menghubungkan container secara aman dan efisien, baik dengan container lain maupun dengan jaringan eksternal. Dengan Docker Networking, container dapat saling berkomunikasi tanpa perlu mengetahui alamat IP secara manual.

Docker menyediakan beberapa jenis Network Driver yang bisa digunakan sesuai kebutuhan:

  • Bridge Network : Container dalam jaringan ini bisa berkomunikasi satu sama lain. Container tidak bisa langsung diakses dari luar kecuali dengan port mapping.
  • Host Network : Container akan menggunakan network host langsung, tanpa isolasi jaringan. Tidak bisa digunakan di Windows dan Mac.
  • None Network : Container tidak akan terhubung ke jaringan manapun.
  • Overlay Network : Digunakan dalam Docker Swarm untuk menghubungkan container di berbagai host (server).
  • Macvlan Network : Container diberikan alamat IP dari jaringan fisik, sehingga bisa berkomunikasi langsung dengan jaringan eksternal.

Berikut merupakan beberapa perintah dasar untuk mengelola Docker Network:

# Melihat daftar Docker Network
docker network ls
 
# Membuat Docker Network, default driver: bridge
docker network create --driver <driver-name> <network-name>
 
# Menghapus Docker Network, (hapus container yg menggunakan-nya terlebih dahulu)
docker network rm <network-name>

Container Network

Setelah membuat network, kita bisa menggunakan network tersebut pada container. Berikut merupakan contoh penggunaan perintah untuk menggunakan Docker Network pada Container:

# Membuat Container dengan Network
docker run --name <container-name> --network <network-name> <image-name>:<tag>
 
# Menghapus(disconnect) Container dari Network
docker network disconnect <network-name> <container-name>
 
# Menambahkan(menyambungkan) Container ke Network
docker network connect <network-name> <container-name>

Berikut merupakan contoh dari penerapan 2 Container yang saling berkomunikasi menggunakan Docker Network:

docker network create mongonetwork # buat network terlebih dahulu
docker container create --name mongodb --network mongonetwork --env ... mongo:latest # buat container mongodb, yg connect ke network mongonetwork
docker container create --name mongodbexpress --network mongonetwork --publish 8081:8081 --env ... mongo-express:latest # buat container mongo-express, yg connect ke network mongonetwork
docker start mongodb # start container
docker start mongodbexpress # start container
# Now try access http://localhost:8081, which is from mongo-express container
# You can access mongodb from mongo-express container, because they are in the same network

Inscpect

Untuk melihat informasi lebih detail tentang Docker Container, Docker Image, Docker Network, dan Docker Volume, kita bisa menggunakan perintah docker inspect. Perintah ini akan menampilkan informasi lengkap tentang objek yang kita inspect. Berikut merupakan contoh penggunaan perintah docker inspect:

# Melihat informasi detail tentang Docker Container
docker container inspect <container-name>
 
# Melihat informasi detail tentang Docker Image
docker image inspect <image-name>:<tag>
 
# Melihat informasi detail tentang Docker Volume
docker volume inspect <volume-name>
 
# Melihat informasi detail tentang Docker Network
docker network inspect <network-name>

Prune

Docker Prune adalah perintah yang digunakan untuk membersihkan objek-objek yang tidak terpakai di Docker. Objek-objek tersebut bisa berupa Docker Container, Docker Image, Docker Volume, dan Docker Network. Perintah ini sangat berguna untuk menghemat resource dan mengoptimalkan kinerja Docker. Berikut merupakan contoh penggunaan perintah docker prune:

# Membersihkan Docker Container yang tidak terpakai
docker container prune
 
# Membersihkan Docker Image yang tidak terpakai
docker image prune
 
# Membersihkan Docker Volume yang tidak terpakai
docker volume prune
 
# Membersihkan Docker Network yang tidak terpakai
docker network prune
 
# Membersihkan semua objek Docker yang tidak terpakai, kecuali volume
docker system prune
 
# Membersihkan semua objek Docker yang tidak terpakai, termasuk volume
docker system prune --volumes

Materi Selanjutnya

  • Dockerfile, untuk membuat Docker Image baru dengan konfigurasi yang kita inginkan.
  • Docker Compose, untuk mengelola multi-container Docker Application dengan file konfigurasi YAML agar lebih mudah.