Melihat memang bukan mengendalikan — dan pertanyaan yang kita tinggalkan di akhir Chapter Melihat Container kini menanti jawaban: bagaimana caranya memadamkan web untuk menghemat resource tanpa membuang container-nya, lalu menyalakannya kembali dalam kondisi yang sama? Sebuah server sungguhan tidak menyala selamanya; ada jendela pemeliharaan, ada penghematan di akhir pekan, ada pula momen darurat ketika sebuah layanan harus dimatikan seketika. Docker menyediakan satu keluarga perintah untuk seluruh keadaan itu — stop, start, restart, kill, dan pause — dan masing-masing bekerja dengan mekanisme yang berbeda di balik layar. Chapter ini membedah kelima perintah tersebut beserta sinyal-sinyal Linux yang menjadi bahasa komunikasi di antaranya, sehingga kita selalu bisa memilih cara mematikan yang tepat untuk situasi yang tepat.

Menghentikan Container dengan docker stop #

Perintah docker stop adalah cara paling sopan untuk mematikan container yang sedang berjalan. Kata “sopan” bukan basa-basi: docker stop memberi kesempatan kepada aplikasi di dalam container untuk beres-beres — menutup koneksi, mem flush penulisan, dan menghentikan dirinya sendiri — sebelum Docker mengambil tindakan paksa. Mari kita matikan web yang sejak Chapter Melihat Container masih setia melayani permintaan HTTP:

bash
$ docker stop web

Output yang Dihasilkan:

text
web

Mari kita telaah perintah dan output di atas:

  1. Output satu baris web — docker stop mencetak kembali identifier yang kita sebut sebagai tanda keberhasilan; baik nama maupun ID pendek sama-sama diterima, dan outputnya pun mengikuti bentuk yang kita pakai.
  2. Bentuk modernnya — sesuai tabel alias pada Chapter Struktur Perintah Docker, perintah ini setara dengan docker container stop; dokumentasi resmi memakai bentuk modern, sementara kedua bentuk menghasilkan efek yang identik.
  3. web tidak terhapus — container hanya berhenti; seluruh konfigurasi, nama, ID, dan isinya tetap berada di tangan daemon, siap dinyalakan ulang kapan pun.

Kita buktikan klaim terakhir itu dengan jendela yang sudah kita kenal:

bash
$ docker ps -a

Output yang Dihasilkan:

text
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                      PORTS      NAMES
f7c2a91b3e55   nginx         "/docker-entrypoint.…"   13 minutes ago   Exited (0) 5 seconds ago              web
3a1c8f2e9b7d   redis:7       "docker-entrypoint.s…"   7 minutes ago    Up 7 minutes                6379/tcp   cache
d4e5f6a7b8c9   hello-world   "/hello"                 15 minutes ago   Exited (0) 15 minutes ago             quirky_einstein

Mari kita telaah tiga baris pada tabel di atas:

  1. Exited (0) 5 seconds ago milik web — status berhenti lengkap dengan kode keluar 0 di dalam kurung; kode 0 berarti proses utama menyelesaikan pematian dengan rapi, dan makna lengkap angka-angka semacam ini kita bedah tuntas pada Chapter Memahami Exit Code.
  2. cache dan quirky_einstein tidak tersentuh — docker stop hanya membidik container yang kita sebutkan; Redis milik cache tetap berjalan, dan quirky_einstein tetap tergeletak dalam keadaan berhenti seperti sejak Chapter Menjalankan Container Pertama.
  3. Kolom PORTS milik web kosong — bukan karena pemetaan 8080->80 hilang; docker ps memang tidak menampilkan pemetaan port untuk container yang sedang berhenti. Pemetaan tersebut tetap tercatat pada konfigurasi container dan akan aktif kembali begitu container dinyalakan.

Lalu apa yang sebenarnya terjadi di balik layar? docker stop mengirim sinyal SIGTERM kepada PID 1 — proses utama container, dalam kasus kita skrip entrypoint nginx — lalu menunggu dengan masa tenggang 10 detik secara default. Bila proses berhasil berhenti sebelum masa tenggang habis, container berhenti dengan anggun. Bila proses justru ngotot tetap hidup, Docker mengirim SIGKILL yang memaksa proses mati tanpa proses penawaran. Diagram berikut memetakan alurnya:

Mari kita telaah setiap tahap pada diagram di atas:

  1. Titik masuk — docker stop tidak membunuh apa pun secara langsung; langkah pertamanya selalu mengirim sinyal sopan dan menunggu.
  2. Titik keputusan — masa tenggang default 10 detik adalah batas atas, bukan durasi tunggu wajib; container yang merespons cepat akan berhenti jauh sebelum batas itu.
  3. Jalur atas — proses yang menghormati sinyal berhenti dengan sendirinya, dan status akhirnya mencerminkan penutupan yang rapi.
  4. Jalur bawah — sinyal SIGKILL tidak bisa ditangkap atau diabaikan oleh proses apa pun; container yang menempuh jalur ini berhenti dalam keadaan dipaksa, dan statusnya berubah menjadi Exited (137) — angka yang artinya kita bongkar nanti.

Menyalakan Kembali dengan docker start #

Container yang berhenti adalah container yang menunggu — dan docker start adalah tombolnya. Perintah ini menghidupkan kembali container yang sudah ada, bukan membuat container baru; bedanya dengan docker run persis seperti bedanya menyalakan kembali komputer lama versus membeli komputer baru. Inilah pemisahan tahap create dan start yang kita janjikan pada Chapter Menjalankan Container Pertama: docker create menyiapkan container tanpa menjalankannya, docker start menghidupkannya, dan docker run hanyalah keduanya digabung:

bash
$ docker start web

Output yang Dihasilkan:

text
web
bash
$ docker ps

Output yang Dihasilkan:

text
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS                                     NAMES
f7c2a91b3e55   nginx     "/docker-entrypoint.…"   15 minutes ago   Up 5 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   web
3a1c8f2e9b7d   redis:7   "docker-entrypoint.s…"   9 minutes ago    Up 9 minutes   6379/tcp                                  cache

Mari kita telaah apa yang barusan terjadi pada kedua output di atas:

  1. docker start mengembalikan identifier yang kita sebut — sama seperti docker stop, output satu baris ini adalah konfirmasi; bila kita memanggil dengan ID pendek f7c2a91b3e55, outputnya pun ID pendek tersebut.
  2. Kolom CREATED tetap 15 minutes ago — waktu pembuatan container tidak pernah berubah oleh stop dan start; yang berubah hanyalah STATUS, yang kini menunjukkan Up 5 seconds karena proses PID 1 baru saja dinyalakan ulang.
  3. Kolom PORTS terisi penuh kembali — pemetaan 0.0.0.0:8080->80/tcp beserta pasangan IPv6-nya menempel pada container, bukan pada sesi terminal; tidak ada docker run baru, tidak ada flag -p yang diketik ulang.
  4. curl localhost:8080 kini menjawab — halaman Welcome to nginx! yang sama persis melayani permintaan berikutnya, karena seluruh konfigurasi dan isi writable layer web tidak tersentuh oleh siklus stop-start ini.

Mengatur Masa Tenggang dengan –time #

Masa tenggang 10 detik cukup untuk hampir semua aplikasi, tetapi tidak untuk semuanya. Aplikasi dengan banyak koneksi berumur panjang, antrian pesan yang harus dikuras, atau basis data yang sedang menulis checkpoint bisa membutuhkan waktu berhenti yang jauh lebih lama. Flag -t atau bentuk panjangnya --time mengubah masa tenggang untuk satu pemanggilan — nilainya dalam detik:

bash
$ docker stop -t 30 web

Output yang Dihasilkan:

text
web

Mari kita telaah perintah di atas:

  1. -t 30 sebelum nama container — kita memberi nginx ruang bernapas sampai 30 detik sebelum SIGKILL diizinkan turun; nilainya menggantikan angka 10 default hanya untuk pemanggilan ini.
  2. Perintah tetap kembali hampir seketika — nginx menutup dirinya dalam hitungan milidetik karena menangani sinyal berhenti dengan rapi; masa tenggang hanyalah batas atas, bukan durasi tunggu yang harus habis.
  3. Kapan angka besar benar-benar dibutuhkan — bayangkan aplikasi yang harus menyelesaikan transaksi setengah jalan sebelum keluar; bila lognya menunjukkan proses berhenti selalu terpotong oleh SIGKILL, angka default-lah yang patut dicurigai.

Kita hidupkan kembali web supaya mesin kita kembali seperti semula untuk latihan-latihan berikutnya:

bash
$ docker start web

Output yang Dihasilkan:

text
web

Menyalakan Ulang dengan docker restart #

Kadang yang kita butuhkan bukan berhenti lalu menyalakan dengan dua perintah, melainkan satu perintah yang melakukan keduanya berurutan. docker restart menghentikan container dengan jalur sopan yang sama seperti docker stop — termasuk masa tenggang yang bisa diatur dengan -t — lalu langsung menyalakannya kembali. Pola ini akrab pada dunia server: mengubah berkas konfigurasi lalu memuat ulang layanannya:

bash
$ docker restart web

Output yang Dihasilkan:

text
web

Untuk membuktikan bahwa proses di dalamnya benar-benar baru, kita manfaatkan kebiasaan --format yang kita pelajari pada Chapter Melihat Container:

bash
$ docker ps --format "{{.Names}}: {{.Status}}"

Output yang Dihasilkan:

text
web: Up 5 seconds
cache: Up 13 minutes

Mari kita telaah kedua baris di atas:

  1. web: Up 5 seconds — proses PID 1 di dalam web baru berumur beberapa detik; docker restart mematikan proses lama dan melahirkan proses baru, bukan sekadar menyegarkan sesuatu di dalam container.
  2. cache: Up 13 minutes — container lain tidak ikut tersentuh, dan umurnya terus berjalan; restart selalu bersifat per container, sesuai identifier yang kita sebutkan.
  3. Container yang sama, bukan container baru — ID, nama, pemetaan port, dan writable layer tetap milik web yang lama; hanya prosesnya yang berganti generasi.

Menghentikan Paksa dengan docker kill #

Semua jalur di atas berbagi satu asumsi: proses di dalam container bersedia berhenti. docker kill membuang asumsi itu — perintah ini mengirim SIGKILL secara langsung, tanpa sinyal peringatan dan tanpa masa tenggang. Proses yang menerima SIGKILL mati seketika di tangan kernel; tidak ada penangan sinyal yang bisa mencegahnya:

bash
$ docker kill web

Output yang Dihasilkan:

text
web
bash
$ docker ps -a

Output yang Dihasilkan:

text
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                       PORTS      NAMES
f7c2a91b3e55   nginx         "/docker-entrypoint.…"   21 minutes ago   Exited (137) 5 seconds ago              web
3a1c8f2e9b7d   redis:7       "docker-entrypoint.s…"   15 minutes ago   Up 15 minutes                6379/tcp   cache
d4e5f6a7b8c9   hello-world   "/hello"                 23 minutes ago   Exited (0) 23 minutes ago               quirky_einstein

Mari kita telaah perbedaan yang paling penting pada tabel di atas:

  1. Exited (137) pada baris web — bandingkan dengan Exited (0) pada sesi docker stop sebelumnya; angka 137 adalah 128 + 9, yaitu konvensi kernel untuk “proses dihentikan oleh sinyal nomor 9 alias SIGKILL” — pembahasan lengkapnya menanti di Chapter Memahami Exit Code.
  2. Dua bekas luka yang berbeda pada satu mesin — web kini tercatat berhenti paksa, sementara quirky_einstein tercatat berhenti rapi; satu kolom STATUS saja sudah cukup untuk membaca sejarah kematian dua container ini.
  3. web tetap tidak terhapus — docker kill mematikan proses, bukan membuang container; ia tetap bisa dinyalakan ulang seperti biasa.
  4. docker kill juga menerima flag --signal — bila kita ingin mengirim sinyal lain seperti SIGHUP atau SIGUSR1 kepada PID 1, flag inilah alatnya; tanpa flag tersebut, SIGKILL adalah pilihan bawaan.

web tidak menyimpan data penting apa pun — halaman statis bawaan nginx — sehingga membangkitkannya kembali dari kematian paksa tidak menyisakan masalah:

bash
$ docker start web

Output yang Dihasilkan:

text
web

Membekukan Container dengan docker pause #

Ada satu keadaan yang belum tercakup keluarga perintah di atas: kita ingin container diam sebentar — bukan mati, hanya berhenti bergerak. docker pause melakukan hal itu dengan mekanisme yang sepenuhnya berbeda dari sinyal: kernel Linux membekukan seluruh proses dalam container lewat freezer cgroup, seperti menekan tombol pause pada pemutar musik. Proses tetap hidup di memori, semua statusnya terjaga, hanya saja tidak mendapat waktu CPU sama sekali:

bash
$ docker pause web

Output yang Dihasilkan:

text
web
bash
$ docker ps

Output yang Dihasilkan:

text
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                  PORTS                                     NAMES
f7c2a91b3e55   nginx     "/docker-entrypoint.…"   23 minutes ago   Up 2 minutes (Paused)   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   web
3a1c8f2e9b7d   redis:7   "docker-entrypoint.s…"   17 minutes ago   Up 17 minutes           6379/tcp                                  cache

Mari kita telaah status barunya:

  1. Up 2 minutes (Paused) — container tetap berstatus hidup, lengkap dengan durasinya, dan kata (Paused) menempel sebagai penanda keadaan beku; bandingkan dengan kill yang mengubah status menjadi Exited.
  2. Pemetaan port tetap terpasang — karena prosesnya masih hidup, kolom PORTS tidak dikosongkan; tetangga di jaringan tetap bisa mengirim paket, hanya tidak ada yang menjawab.

Dan di sinilah muncul gejala yang tidak terlupakan: coba jalankan curl localhost:8080 sekarang. Koneksi TCP berhasil dibuka — handshake dijawab oleh jaringan kernel — tetapi permintaan HTTP kita tidak pernah mendapat balasan, karena nginx di dalam container sedang beku dan tidak membaca apa pun. Terminal tampak menggantung di tengah; tekan Ctrl-C untuk melepaskannya. Kita cairkan kembali container-nya:

bash
$ docker unpause web

Output yang Dihasilkan:

text
web

Proses di dalam web melanjutkan eksekusi persis dari titik pembekuan, dan curl localhost:8080 kembali menjawab halaman selamat datang seperti biasa. Tidak ada proses yang mati, tidak ada yang dimulai ulang — hanya jeda yang tidak dirasakan siapa pun di dalam container.

Memilih antara stop, kill, dan pause #

Lima perintah pada chapter ini terasa serupa di permukaan — semuanya “mengurus container yang sedang hidup” — tetapi bekerja pada mekanisme yang sama sekali berbeda. Tabel berikut merangkum lima aspek yang membedakan ketiga jalur utamanya:

Aspekdocker stopdocker killdocker pause
Sinyal yang dikirimSIGTERM atau sinyal STOPSIGNAL image, lalu SIGKILL bila perluSIGKILL langsungTidak ada sinyal — freezer cgroup
Masa tenggang10 detik default, dapat diubah dengan -tTidak adaTidak relevan
Nasib prosesBerhenti totalBerhenti totalTetap hidup namun dibekukan
Status di docker psExited dengan kode aplikasi, umumnya Exited (0)Exited (137)Up … (Paused)
Kapan dipakaiMematikan container secara sopan sehari-hariKeadaan darurat atau container yang macetMembekukan beban untuk pemeriksaan

Aturan praktisnya sederhana: docker stop adalah pilihan bawaan untuk segala pematian yang tidak mendesak, docker kill adalah pemecah kebuntuan ketika sopan santun sudah tidak mempan, dan docker pause adalah tombol jeda yang tidak membunuh siapa pun. Kini kita mahir mengendalikan hidup-mati container, tetapi satu masalah pelan-pelan menumpuk di sudut mesin: setiap siklus stop yang kita jalankan hari ini meninggalkan container berhenti yang terus tercatat di docker ps -a, dan quirky_einstein sudah lama menjadi penghuninya. Chapter berikutnya, Menghapus Container, membereskan jejak-jejak itu dengan docker rm, flag --rm, dan docker container prune — sekaligus membahas apa yang sebenarnya ikut terbuang saat sebuah container dihapus.

Referensi #