Ingin mencoba nginx, ruby, atau golang tapi males repot menginstal dan menghapusnya nanti? Dengan Docker, kita bisa langsung menjalankan aplikasi tanpa harus pusing dengan proses instalasi atau bersih-bersih setelahnya.
Mengunduh image bikinan orang lain
image adalah semacam "installer". Dari image ini, kita bisa menginstallnya sebagai container, yaitu aplikasi yang siap dijalankan. Kita bisa membuat image sendiri, tapi konfigurasi dan proses build membutuhkan waktu lama. Dengan kepakaran yang terbatas, lebih praktis memanfaatkan image bikinan orang lain.
image yang telah dibangun oleh orang lain dapat diperoleh dari Docker Hub. Semacam toko aplikasi atau "App Store" yang di dalamnya telah diorganisasi dengan rapi. Misalnya, kategori "Language & Frameworks" berisikan image dari bahasa php atau ruby yang lumayan ribet jika menginstall secara manual.
Namun, berkat docker kita bisa dengan mudah gunakan image tersebut dengan docker pull NAMA_IMAGE. Contohnya:
docker pull ruby
Kemudian mengecek daftar image dengan perintah
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ruby latest dc4e58bf5fd5 5 weeks ago 1.46GB
Menghapus image
Image yang tidak dipakai lebih baik dihapus daripada menghabiskan ruang.
Misalnya terdapat image dengan nama nginx. Dua cara menghapusnya, yaitu:
docker image rm nginx
- Cara cepat (rmi = remove image)
docker rmi nginx
Menjalankan container
Image adalah sekumpulan aplikasi yang tersedia namun belum siap digunakan, semacam "installer".
Sebelum dijalankan, image perlu dipasang/ diinstall ke sistem sebagai container.
Sebuah image dapat dipasang sebagai beberapa container.
Terdapat dua jenis kontainer:
- Kontainer layanan siaga: kontainer dengan layanan latar (background service)
- Kontainer buruh: kontainer aplikasi
Kontainer Layanan Siaga
Aplikasi semacam server web, menjalankan proses latar. Di balik layar (tanpa antar muka), proses tersebut berjalan standby menunggu permintaan dari pengguna.
Biasanya aplikasi semacam ini menerima permintaan melalui protokol TCP/IP (aplikasi jaringan) dan HTTP (aplikasi web).
Contohnya, aplikasi nginx memonitor port 80 (bisa diganti di konfigurasi). Selama hidupnya, nginx akan menguasai port 80 sehingga aplikasi lain tidak dapat menggunakannya (port binding).
Perintah berikut akan melakukan tiga hal:
- Mengunduh image
nginx dari "Docker Hub" jika belum tersedia di komputer lokal.
- Membuat container baru dengan nama otomatis
- Menjalankan container tersebut.
docker run -d -p 80:80 nginx
-d atau --detachmenandakan bahwa proses dijalankan dilatar ("detach" berarti pengguna tidak perlu menunggu dan menanti sampai kisah ini berakhir).
[!important] Dalam dunia sistem komputer, kita juga mengenal istilah daemon, yaitu proses yang bergentayangan di balik layar.
nginx mangkal di port 80 di dalam kontainer dan siap siaga. Namun, untuk meminta data dari nginx, kita perlu masuk ke dalam kontainer tersebut. Ini akan kita bahas lain waktu. Kita pelajari dulu cara mengakses layanan ini tanpa masuk-masuk.
-p atau --publish berarti layanan yang ada di dalam kontainer akan dipublikasikan oleh host (komputer yang menjalankan kontainer), sehingga bisa diakses tanpa harus masuk ke dalam kontainer.
Kita bisa menggunakan browser dan mengambil file yang tersedia melalui broser dengan alamat URL http://127.0.0.1:80 atau http://127.0.0.1 (:80 adalah port default untuk protokol HTTP).
# Welcome to nginx!
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.
For online documentation and support please refer to [nginx.org](http://nginx.org/).
Commercial support is available at [nginx.com](http://nginx.com/).
_Thank you for using nginx._
Orang siaga ada batasnya, ada masa-masa dimana aplikasi membutuhkan "me time".
Apakah aplikasi sedang siaga? Pertanyaan bisa dijawab dengan mudah menggunakan perintah berikut:
docker ps
ps adalah perintah umum di linux yang merupakan singkatan dari proses status.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24b57acffb5b nginx "/docker-entrypoint.…" 16 minutes ago Up 16 minutes 0.0.0.0:80->80/tcp pedantic_sinoussi
Dari luaran di atas, proses dari kontainer nginx sedang berjalan dengan port yang dipublikasikan di 0.0.0.0:80.
[!note] Dalam jaringan dengan TCP-IP, setiap komputer diberi nama menggunakan alamat IP.
Alamat khusus "127.0.0.1" (loopback interface) digunakan untuk menyebut "komputer ini" secara spesific.
Sedangkan "0.0.0.0" (unspecified address) menunjukkan bahwa aplikasi akan melayani "siapapun".
Layanan web sudah berjalan, tapi bagaimana jika file HTML nya ada di laptop (host).
Bayangkan kontainer seperti sebuah komputer yang ada didalam komputer yang sedang kita gunakan. Terdapat dua sistem penyimpanan file, satu di container, dan satu lagi di host.
Supaya layanan nginx dapat membaca file yang ada di host, docker membutuhkan pemetaan dari sistem file host dengan container.
Docker menyediakan parameter -v atau --volume untuk memetakan volume yang ada di host ke container. Pada linux, volume adalah lokasi logis sebuah media penyimpanan. Misalnya kita memiliki sebuah media penyimpanan fisik yaitu sebuah harddisk. Harddisk dapat dipartisi menjadi dua volume. Pada Microsoft Windows, volume adalah drive, misalnya drive C dan D. Alamat dari sebuah volume biasa disebut path, misalnya c:\ dan d:\.
Sehingga, path dibutuhkan untuk menyampaikan memberitahu pemetaan lokasi penyimpanan dari host ke container.
Sintaksnya adalah -v host_path:container_path
Pertama, siapkan dulu dokumen html di komputer yang sedang dipakai. ~/ adalah lokasi data dari user yang sedang login.
Misalnya, ketika login sebagai user aku di Linux,
- maka
~/ sama dengan /home/aku
- atau pada MacOS lokasinya adalah
/Users/aku
mkdir -p ~/Projects/html
vim ~/Projects/html/index.html
Lalu jalankan layanan nginx dengan memetakan:
- Dari lokasi
~/Projects/html pada host
- Ke
/usr/share/nginx/html dalam container
Secara default, nginx akan menyajikan semua file yang ada di /usr/share/nginx/html. Lebih detail dijelaskan pada dokumentasi image nginx di hub.docker.com/_/nginx
docker run -d -p 80:80 --name nginxdocker -v ~/Projects/html:/usr/share/nginx/html nginx
Cek di browser http://127.0.0.1 dan pastikan tampilannya sama dengan isi dari ~/Projects/html/index.html.
Kontainer Buruh
Berbeda dengan nginx yang menyediakan layanan siaga, aplikasi semacam php dan ruby hanya bekerja ketika diperintah.
[!tip] Hal ini sangat jarang dilakukan karena biasanya kita menggunakan docker untuk menyediakan layanan.
Ssaat development, semua aplikasi (php, ruby) biasanya sudah terinstall.
Contohnya, menjalankan aplikasi ruby dalam mode interactive dan tty -it, langsung dari dalam kontainer. Dalam mode interactive -i, klien docker akan menunggu masukan (input). Ditambah mode tty -t, docker juga akan menampilkan luaran (output) dari aplikasi yang dijalankan.
docker run -it ruby
irb(main):003> x="hello"
=> "hello"
irb(main):004> puts x
hello
=> nil
irb(main):005> exit
Cocok buat coba-coba tanpa merusak sistem di komputer lokal.
Menjalankan aplikasi di dalam kontainer
Bayangkan container sebagai komputer di dalam komputer yang sedang kita gunakan. Komputer yang menjalankan container, disebut sebagai host.
Jika dalam host kita menjalankan aplikasi ruby dengan perintah berikut (-e menandakan eksekusi argumen berikutnya, yaitu "puts 'hello'"):
ruby -e "puts 'hello'"
Aplikasi di dalam kontainer dapat dijalankan secara langsung, dengan perintah yang mirip, dengan menjalankan docker run nama_image.
[!note] Ingat: docker run Membuat dan menjalankan kontainer baru dari image
docker run ruby ruby -e "puts 'hello'"
Setelah aplikasi di dalam kontainer selesai dieksekusi, proses kontainer akan distop namun kontainer TIDAK dihapus.
Cek sendiri kalau tidak percaya.
docker ps
docker container ls -a
Dalam contoh berikut, terdapat tiga container yang telah berhenti Exited (0) dengan nama flamboyant_hellman, admiring_panini, xenodochial_driscoll.
Docker selalu membuat kontainer baru dengan nama otomatis karena kita tidak memberikan nama.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f1678868ff5d ruby "ruby -e 'puts 'hell…" 37 seconds ago Exited (0) 36 seconds ago flamboyant_hellman
c4c40fd1dbeb ruby "ruby -e 'puts 'hell…" 39 seconds ago Exited (0) 39 seconds ago admiring_panini
6029346e8df7 ruby "ruby -e 'puts 'hell…" 43 seconds ago Exited (0) 42 seconds ago xenodochial_driscoll
Kalau mau bersih-bersih, docker rm bisa dipakai untuk menghapusnya:
docker rm NAMA_CONTAINER
Atu jalur gampang nan berbahaya, hapus semua docker yang sudah tidak berjalan dengan prune (pangkas).
docker container prune
Sekarang, bagaimana caranya agar setiap menjalankan docker run, tidak menghasilkan kontainer baru.
Cara pertama adalah dengan otomatis menghapus container setelah dijalankan, dengan memberi tanda --rm
docker run --rm ruby ruby -e "puts 'hello'"
Cara kedua adalah dengan memberikan nama kontainer dengan argumen --name.
Berikut sintaksnya:
docker run --name NAMA_CONTAINER NAMA_IMAGE PERINTAH
Sebagai contoh:
docker run --name rubydocker ruby ruby -e "puts 'hello'"
Setiap perintah di atas dijalankan, maka docker akan mencoba memanfaatkan container yang sudah ada dengan nama yang diberikan.
docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7d9ffbc6aab7 ruby "ruby -e 'puts 'hell…" 27 seconds ago Exited (0) 26 seconds ago rubydocker
Disini hanya terdapat satu kontainer bernama rubydocker.
Perintah docker run yang sama, tidak dapat dijalankan lagi karena kontainer ini sudah ada.
❯ docker run --name rubydocker ruby ruby -e "puts 'hello'"
docker: Error response from daemon: Conflict. The container name "/rubydocker" is already in use by container "7d9ffbc6aab70355725fb8e57c1c63475d8fb0834f6ce83c5658b13c6fd9edc0". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
Sehingga, untuk memanfaatkan kembali kontainer ini digunakan perintah docker start NAMA_CONTAINER.
Namun, pada "kontainer buruh", proses ini hanya berjalan sesaat kemudian keluar lagi, karena tidak ada perintah yang diberikan.
Perintah dapat diberikan dengan menggunakan operasi pipe |. Sintaksnya perintah_pertama | perintah_kedua. Proses dari perintah pertama akan menjadi masukan bagi perintah kedua.
docker start rubydocker | ruby -e "puts 'hello'"
Mulai ribet kan?
Demi kenyamanan bersama, perintah panjang ini bisa dijadikan pendek dengan alias.
alias druby="docker start rubydocker | ruby $1"
Sehingga bisa perintahnya menjadi
druby -e "puts 'hello'"
Sekarang kita bisa menjalankan perintah ruby tanpa harus menginstallnya.
Misal terdapat skrip hello.rb pada komputer. Skrip ini bisa dijalankan dengan perintah:
druby hello.rb
Tapi ingat, setiap eksekusi perintah ini akan ada biaya tambahan (overhead cost) untuk menjalankan container.
❯ time druby test.rb
hello
docker start rubydocker 0.01s user 0.01s system 9% cpu 0.233 total
ruby test.rb 0.04s user 0.01s system 96% cpu 0.055 total
❯ time ruby test.rb
hello
ruby test.rb 0.04s user 0.01s system 95% cpu 0.055 total
Ringkasan
Kontainer Layanan
Contoh: Menjalankan server web nginx
- Siapkan dokumen html
mkdir -p ~/Projects/html
vim ~/Projects/html/index.html
- Lalu jalankan layanan
docker run -d -p 80:80 --name nginxdocker -v ~/Projects/html:/usr/share/nginx/html nginx
- Cek di browser
http://127.0.0.1
Kontainer Buruh
Menjalankan aplikasi: berikut contoh untuk ruby. Bisa diterapkan untuk aplikasi lain, tinggal mengganti ruby dengan php, python, dll.
docker run --name rubydocker ruby ruby -e "puts 'hello'"
alias druby="docker start rubydocker | ruby $1"
druby -e "puts 'hello'"
druby hello.rb
Bonus
Aplikasi biasanya dikemas sebagai image dalam sistem operasi Debian, yang dilengkapi dengan paket lengkap sehingga ukurannya cukup besar. Namun, kebutuhan dasar aplikasi umumnya dapat dipenuhi dengan paket yang lebih ringan dari distribusi seperti Debian Bookworm atau Linux Alpine.
Contohnya, aplikasi ruby yang dikemas dalam Debian Bookworm dapat dijalankan dengan menambahkan tag slim, sehingga nama imagenya menjadi ruby:slim. Tag selengkapnya dapat di cek di hub.docker.com/_/ruby
docker run --name rubydockerslim ruby:slim ruby -e "puts 'hello'"
Berikut adalah perbandingan ukuran aplikasi yang didistribusikan dengan tag latest, alpine atau slim:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 048e09038596 10 days ago 197MB
nginx alpine 577a23b5858b 10 days ago 50.8MB
php latest 910138e230ec 2 weeks ago 530MB
php alpine b6ec2c8a30cb 2 weeks ago 96.7MB
ruby latest febc5e18cba3 5 weeks ago 1GB
ruby slim 137ca6ff3afb 5 weeks ago 212MB
ruby alpine e78475f17fab 5 weeks ago 92.5MB