CMD vs ENTRYPOINT

Perbedaan perintah default yang dapat diganti dan entrypoint tetap, beserta pola gabungan keduanya.

Daftar isi

CMD dan ENTRYPOINT sama-sama menetapkan perintah yang dieksekusi ketika container dibuat dari image, tetapi keduanya berbeda perilaku saat docker run menerima argumen tambahan. CMD menyimpan perintah default yang dapat diganti penuh oleh argumen tersebut, sedangkan entrypoint, perintah tetap yang tercatat pada image, mempertahankan bagian perintah yang tidak boleh berganti dan memperlakukan argumen sebagai tambahannya. Topik ini membedah bentuk penulisan perintah, perilaku penggantian atau override, yaitu penggantian nilai bawaan image pada saat container dijalankan, serta pola gabungan keduanya pada image aplikasi catatan.

Shell form dan exec form#

Perintah pada CMD maupun ENTRYPOINT dapat ditulis dalam dua bentuk, sehingga bentuknya perlu dipahami terlebih dahulu. Shell form menuliskan perintah sebagai teks biasa, sedangkan exec form menuliskannya sebagai array JSON.

dockerfile Contoh: CMD dalam shell form
CMD python3 app.py
dockerfile Contoh: CMD dalam exec form
CMD ["python3", "app.py"]

Pada shell form, Docker membungkus perintah dengan /bin/sh -c, sehingga proses utama container adalah shell, bukan aplikasinya. Sinyal penghentian yang dikirim docker stop diterima shell terlebih dahulu, dan shell tidak meneruskannya ke aplikasi. Akibatnya, aplikasi tidak sempat membereskan koneksi yang sedang berjalan sebelum dihentikan paksa setelah batas waktu. Pada exec form, program dijalankan langsung tanpa perantara, sehingga python3 menjadi proses utama dan menerima sinyal penghentian secara langsung. Karena alasan itulah exec form menjadi bentuk yang disarankan untuk CMD maupun ENTRYPOINT.

Konsekuensi lain dari exec form adalah ketiadaan penafsiran shell, sehingga konstruksi seperti variabel $PORT dan pemipaan tidak ditafsirkan. Apabila penafsiran shell benar-benar diperlukan, penulisan eksplisit seperti ["/bin/sh", "-c", "python3 app.py"] membuatnya terlihat pada Dockerfile. Untuk aplikasi catatan, bentuk exec langsung digunakan tanpa perantara shell.

CMD, perintah default yang dapat diganti#

CMD menyimpan perintah default yang dieksekusi ketika docker run tidak diberi argumen tambahan. Argumen yang ditulis setelah nama image pada docker run mengganti CMD sepenuhnya, bukan menambahkannya. Perilaku inilah yang memungkinkan satu image digunakan untuk beberapa keperluan, misalnya memeriksa versi Python atau membuka shell alih-alih menjalankan aplikasi.

bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# tanpa argumen tambahan, CMD dari image dieksekusi
docker run --rm aplikasi-catatan
# argumen setelah nama image mengganti CMD sepenuhnya
docker run --rm aplikasi-catatan python3 --version
docker run --rm aplikasi-catatan sh

Baris kedua pada blok di atas mengeksekusi python3 --version di dalam container, sedangkan baris ketiga membuka shell. Keduanya tidak pernah menyentuh app.py, karena seluruh CMD dari image sudah digantikan. Penggantian ini hanya berlaku pada container tersebut, sedangkan image tetap menyimpan CMD aslinya.

ENTRYPOINT, perintah tetap#

ENTRYPOINT menetapkan perintah yang tetap dieksekusi dan memperlakukan CMD sebagai argumen defaultnya. Argumen tambahan pada docker run tetap mengganti CMD, tetapi hasil penggantinya kini diteruskan ke entrypoint sebagai argumen. Pola baku yang menggabungkan keduanya menuliskan program pada ENTRYPOINT dan nilai defaultnya pada CMD.

dockerfile Contoh: pola gabungan ENTRYPOINT dan CMD
ENTRYPOINT ["python3"]
CMD ["app.py"]

Dengan konfigurasi tersebut, docker run tanpa argumen mengeksekusi python3 app.py, sedangkan docker run dengan argumen --version mengeksekusi python3 --version. Program tetap python3, dan hanya bagian argumennya yang berganti. Apabila entrypoint sendiri perlu diganti, misalnya untuk membuka shell, opsi --entrypoint pada docker run menggantinya untuk container tersebut tanpa mengubah image.

bash
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# argumen tambahan diteruskan ke entrypoint sebagai pengganti CMD
docker run --rm aplikasi-catatan --version
# opsi --entrypoint mengganti entrypoint untuk container ini saja
docker run --rm --entrypoint sh aplikasi-catatan

Perilaku kombinasi CMD dan ENTRYPOINT#

Perilaku keduanya dirangkum pada tabel berikut, dengan aplikasi-catatan sebagai nama image yang konfigurasinya tercantum pada kolom pertama.

Konfigurasi imagePerintah docker runPerintah yang dieksekusi container
CMD ["python3", "app.py"]docker run --rm aplikasi-catatanpython3 app.py
CMD ["python3", "app.py"]docker run --rm aplikasi-catatan python3 --versionpython3 --version
ENTRYPOINT ["python3"] dan CMD ["app.py"]docker run --rm aplikasi-catatanpython3 app.py
ENTRYPOINT ["python3"] dan CMD ["app.py"]docker run --rm aplikasi-catatan --versionpython3 --version
ENTRYPOINT ["python3"] dan CMD ["app.py"]docker run --rm --entrypoint sh aplikasi-catatansh

Dua baris pertama memperlihatkan CMD saja, yang seluruhnya digantikan oleh argumen docker run. Tiga baris berikutnya memperlihatkan pola gabungan, yang mempertahankan entrypoint dan hanya mengganti bagian argumennya. Baris terakhir memperlihatkan bahwa --entrypoint mengganti bahkan bagian yang tetap, sehingga shell tetap dapat dibuka saat diperlukan.

Kesalahan umum#

  • Aplikasi ditulis dalam shell form, sehingga docker stop terasa lambat dan container selalu berakhir dengan penghentian paksa setelah masa tenggang. Penyebabnya adalah sinyal yang berhenti di shell, bukan di aplikasi. Perbaikannya adalah menuliskan CMD dalam exec form sebagaimana contoh ["python3", "app.py"].
  • Exec form ditulis dengan tanda kutip tunggal atau tanpa tanda kutip, misalnya CMD [python3, app.py]. Bentuk array pada Dockerfile mengikuti konvensi JSON, sehingga tanda kutip ganda wajib dan penulisan lain memicu error saat build.
  • Argumen ditulis untuk mengganti perintah, tetapi image memakai pola gabungan ENTRYPOINT dan CMD. Hasilnya bukan penggantian program, melainkan pengiriman argumen baru ke entrypoint, misalnya python3 python3 --version. Perbaikannya adalah mengganti entrypoint dengan opsi --entrypoint terlebih dahulu, atau menerima perilaku pengiriman argumen bila memang itulah tujuannya.
  • Variabel lingkungan ditulis di dalam exec form dengan harapan ditafsirkan, misalnya ["python3", "app.py", "--port", "${APP_PORT}"]. Exec form tidak memakai shell, sehingga variabel itu tetap sebagai teks. Penafsiran dinyatakan secara eksplisit melalui ["/bin/sh", "-c", "..."] atau dipindahkan ke mekanisme konfigurasi aplikasi.

Ringkasan#

  • Shell form membungkus perintah dengan /bin/sh -c sehingga sinyal penghentian tidak sampai ke aplikasi, sedangkan exec form menjalankan program langsung sebagai proses utama.
  • CMD adalah perintah default yang diganti penuh oleh argumen setelah nama image pada docker run.
  • ENTRYPOINT menahan program tetap dan memperlakukan CMD beserta penggantinya sebagai argumen, dengan pola baku ENTRYPOINT ["python3"] dan CMD ["app.py"].

Referensi#