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.
CMD python3 app.pyCMD ["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.
# 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 shBaris 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.
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.
# 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-catatanPerilaku kombinasi CMD dan ENTRYPOINT#
Perilaku keduanya dirangkum pada tabel berikut, dengan aplikasi-catatan sebagai nama image yang konfigurasinya tercantum pada kolom pertama.
| Konfigurasi image | Perintah docker run | Perintah yang dieksekusi container |
|---|---|---|
CMD ["python3", "app.py"] | docker run --rm aplikasi-catatan | python3 app.py |
CMD ["python3", "app.py"] | docker run --rm aplikasi-catatan python3 --version | python3 --version |
ENTRYPOINT ["python3"] dan CMD ["app.py"] | docker run --rm aplikasi-catatan | python3 app.py |
ENTRYPOINT ["python3"] dan CMD ["app.py"] | docker run --rm aplikasi-catatan --version | python3 --version |
ENTRYPOINT ["python3"] dan CMD ["app.py"] | docker run --rm --entrypoint sh aplikasi-catatan | sh |
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 stopterasa 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--entrypointterlebih 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 -csehingga 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"]danCMD ["app.py"].
Referensi#
- Dockerfile reference — Docker Docs — Menetapkan perilaku CMD, bentuk shell dan exec, serta penggantinya pada docker run.
- Dockerfile reference — Docker Docs — Menetapkan perilaku ENTRYPOINT, interaksinya dengan CMD, dan contoh exec form.