Apa perbedaan antara CMD dan ENTRYPOINT di Dockerfile?


1698

Di Dockerfiles ada dua perintah yang terlihat mirip dengan saya: CMDdan ENTRYPOINT. Tapi saya kira ada perbedaan (halus?) Di antara mereka - jika tidak, tidak masuk akal untuk memiliki dua perintah untuk hal yang sama.

Dokumentasi menyatakan untuk CMD

Tujuan utama CMD adalah untuk menyediakan standar untuk wadah pelaksana.

dan untuk ENTRYPOINT:

ENTRYPOINT membantu Anda mengonfigurasi wadah yang dapat Anda jalankan sebagai yang dapat dieksekusi.

Jadi, apa perbedaan antara kedua perintah itu?


12
Posting blog ini memiliki deskripsi yang baik tentang perbedaan dan bagaimana mereka dapat digunakan bersama juga: crosbymichael.com/dockerfile-best-practices.html .
slm

2
^ itu! Terima kasih @slm. Berikut referensi lain yang sangat mirip yang mungkin sedikit lebih mutakhir: docs.docker.com/reference/builder/#entrypoint
Adam Monsen


1
Tautan ini memberikan perbedaan antara RUN, CMD, dan ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi

1
@JaimeHablutzel Ungkapannya adalah tolonglah sendiri
Jonathan Komar

Jawaban:


1738

Docker memiliki titik masuk default yaitu /bin/sh -c tetapi tidak memiliki perintah standar.

Ketika Anda menjalankan buruh pelabuhan seperti ini: docker run -i -t ubuntu bash titik masuk adalah default /bin/sh -c, gambar adalah ubuntudan perintahnya adalahbash .

Perintah dijalankan melalui titik masuk. yaitu, hal aktual yang dieksekusi adalah /bin/sh -c bash. Ini memungkinkan Docker untuk menerapkanRUN dengan cepat dengan mengandalkan parser shell.

Kemudian, orang-orang meminta untuk dapat menyesuaikan ini, jadi ENTRYPOINTdan --entrypointdiperkenalkan.

Semuanya setelah ubuntudalam contoh di atas adalah perintah dan diteruskan ke titik masuk. Saat menggunakan CMDinstruksi, persis seperti yang Anda lakukan docker run -i -t ubuntu <cmd>. <cmd>akan menjadi parameter dari titik masuk.

Anda juga akan mendapatkan hasil yang sama jika Anda mengetik perintah ini docker run -i -t ubuntu. Anda masih akan memulai bash shell dalam wadah karena Dockerfile ubuntu menentukan CMD default:CMD ["bash"]

Karena semuanya dilewatkan ke titik masuk, Anda dapat memiliki perilaku yang sangat baik dari gambar Anda. @Jiri contohnya bagus, ini menunjukkan cara menggunakan gambar sebagai "biner". Saat menggunakan ["/bin/cat"]sebagai titik masuk dan kemudian lakukandocker run img /etc/passwd , Anda mendapatkannya, /etc/passwdadalah perintah dan diteruskan ke entrypoint sehingga eksekusi hasil akhirnya hanyalah/bin/cat /etc/passwd .

Contoh lain adalah memiliki cli sebagai titik masuk. Misalnya, jika Anda memiliki gambar Redis, bukan berjalan docker run redisimg redis -H something -u toto get key, Anda bisa hanya memiliki ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]dan kemudian jalankan seperti ini untuk hasil yang sama: docker run redisimg get key.


3
Tidak semuanya. ENTRYPOINT menetapkan metadata yang dapat (tetapi dapat diganti) pada saat runtime, jadi jika Anda tidak mengubah apa pun, setelah memulai wadah Anda, hasilnya akan sama, namun, RUN akan ditampilkan pada waktu pembuatan dan apa pun yang Anda lakukan lakukan saat runtime, itu akan ada di sini.
Creack

8
Secara default tidak ada ENTRYPOINT; apakah shell digunakan tergantung pada bentuk CMDperintah yang digunakan ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade

19
Terima kasih untuk ini, konteks historis sangat membantu ketika saya berjuang untuk mengingat aturan yang tampaknya misterius tentang apa yang ditimpa dan apa yang ditambahkan dll. Poin yang berguna untuk penulis dokumentasi teknis di mana-mana: membantu pembaca membangun model mental sistem, jangan hanya daftar fakta dan skenario :-)
ashirley

84
Ini jawaban yang luar biasa. Saya pikir dokumentasi Docker harus menambahkan ini di bawah bagian yang disebut CMDvs ENTRYPOINT.
Tarik

5
@ Webman No. Mereka adalah dua instruksi yang berbeda. Jika keduanya ada, CMD akan diperlakukan sebagai parameter ENTRYPOINT.
Light.G

628

The ENTRYPOINTmenspesifikasikan perintah yang akan selalu dijalankan ketika wadah dimulai.

The CMDmenspesifikasikan argumen yang akan diumpankan ke ENTRYPOINT.

Jika Anda ingin membuat gambar yang didedikasikan untuk perintah tertentu yang akan Anda gunakan ENTRYPOINT ["/path/dedicated_command"]

Jika tidak, jika Anda ingin membuat gambar untuk tujuan umum, Anda dapat meninggalkan yang ENTRYPOINTtidak ditentukan dan menggunakannya CMD ["/path/dedicated_command"]karena Anda akan dapat menimpa pengaturan dengan memberikan argumen docker run.

Misalnya, jika Dockerfile Anda adalah:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]

Menjalankan gambar tanpa argumen apa pun akan melakukan ping ke localhost:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms

Sekarang, menjalankan gambar dengan argumen akan mem-ping argumen:

$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms

Sebagai perbandingan, jika Dockerfile Anda adalah:

FROM debian:wheezy
CMD ["/bin/ping", "localhost"]

Menjalankan gambar tanpa argumen apa pun akan melakukan ping ke localhost:

$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms

Tetapi menjalankan gambar dengan argumen akan menjalankan argumen:

docker run -it test bash
root@e8bb7249b843:/#

Lihat artikel ini dari Brian DeHamer untuk detail lebih lanjut: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/


219
The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT.adalah ringkasan to-the-point yang baik.
Jingguo Yao

1
ENTRYPOINT juga dapat diganti menggunakan flag --entrypoint. untuk misal buruh pelabuhan jalankan -it --entrypoint bash test
seenimurugan

2
Saya suka contoh Anda, ini sangat membantu!
Chau Giang

2
@Jingguo Yao: Bagaimana jika CMD berisi perintah seperti - CMD ["nginx", "- g", "daemon", "off"]? Apakah akan dirantai?
KMC

@KMC CMD adalah argumen default ENTRYPOINT, Anda menimpanya dengan memberikan argumen baru saat menjalankan gambar.
MGP

237

Menurut dok buruh pelabuhan ,

Baik instruksi CMD dan ENTRYPOINT menentukan perintah apa yang dijalankan ketika menjalankan sebuah wadah. Ada beberapa aturan yang menggambarkan kerja sama mereka.

  1. Dockerfile harus menentukan setidaknya satu CMDatau ENTRYPOINTperintah.
  2. ENTRYPOINT harus didefinisikan saat menggunakan wadah sebagai yang dapat dieksekusi.
  3. CMDharus digunakan sebagai cara mendefinisikan argumen default untuk suatu ENTRYPOINTperintah atau untuk mengeksekusi perintah ad-hoc dalam sebuah wadah.
  4. CMD akan diganti ketika menjalankan wadah dengan argumen alternatif.

Tabel di bawah ini menunjukkan perintah apa yang dijalankan untuk ENTRYPOINT/ CMDkombinasi yang berbeda :

- No ENTRYPOINT

╔════════════════════════════╦═════════════════════════════╗
║ No CMD                     ║ error, not allowed          ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════╝

- ENTRYPOINT exec_entry p1_entry

╔════════════════════════════╦══════════════════════════════════╗
║ No CMD                     ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

- ENTRYPOINT [“exec_entry”, “p1_entry”]

╔════════════════════════════╦═════════════════════════════════════════════════╗
║ No CMD                     ║ exec_entry p1_entry                             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“exec_cmd”, “p1_cmd”] ║ exec_entry p1_entry exec_cmd p1_cmd             ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ exec_entry p1_entry p1_cmd p2_cmd               ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

Apa itu px_cmd dan exec_entry? Apa artinya ketika mereka berada di jalur eksekusi yang sama? Mereka dilewatkan sebagai argumen satu sama lain? Bahkan ketika /bin/sh -cterlibat?
Danielo515

1
@ Danielo515 Baik 'px_cmd' dan 'exec_entry' hanyalah string dummy di sini. Anda mungkin melihat bahwa /bin/sh -cakan ditambahkan ke CMD sebagai awalan sementara CMD ditulis dalam sintaks yang dapat dieksekusi (bukan sintaksis daftar).
Ringan.G

1
@royki Jika pengguna menentukan argumen untuk menjalankan docker maka mereka akan menimpa default yang ditentukan dalam CMD.
donrondadon

2
ENTRYPOINT exec_entry p1_entsalah dijelaskan. Formulir shell mencegah CMD atau menjalankan argumen baris perintah agar tidak digunakan - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak

1
@MariuszMiesiak sekarang diperbarui. Terima kasih atas tanggapan Anda.
Rafaf Tahsin

170

Ya, itu pertanyaan yang bagus. Saya belum memahaminya sepenuhnya, tetapi:

Saya mengerti bahwa itu ENTRYPOINTadalah biner yang dieksekusi. Anda dapat mengesampingkan entrypoint dengan --entrypoint = "".

docker run -t -i --entrypoint="/bin/bash" ubuntu

CMD adalah argumen default untuk penampung. Tanpa titik masuk, argumen default adalah perintah yang dieksekusi. Dengan entrypoint, cmd dilewatkan ke entrypoint sebagai argumen. Anda dapat meniru suatu perintah dengan titik masuk.

# no entrypoint
docker run ubuntu /bin/cat /etc/passwd

# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd

Jadi, keuntungan utama adalah bahwa dengan entrypoint Anda dapat meneruskan argumen (cmd) ke wadah Anda. Untuk mencapai ini, Anda perlu menggunakan keduanya:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]

dan

docker build -t=cat .

maka Anda dapat menggunakan:

docker run cat /etc/passwd
#              ^^^^^^^^^^^
#                   CMD
#          ^^^      
#          image (tag)- using the default ENTRYPOINT

@ Blauhirn Dalam kasus Anda, Anda harus menambahkan argumen ke CMD dalam sintaksis daftar, dan pastikan entri Anda sepcified dapat mengurai argumen Anda dalam CMD. Biasanya, saya menambahkan argumen '-h' ke titik masuk. Kemudian saya dapat mengeksekusi docker run image_name -huntuk menunjukkan beberapa informasi bantuan dari gambar ini.
Light.G

1
Ini adalah jawaban yang paling sederhana & jelas.
Eric Wang

44

Perbedaan antara CMD dan ENTRYPOINT berdasarkan intuisi :

  • ENTRYPOINT: perintah untuk dijalankan ketika kontainer mulai.
  • CMD: perintah untuk dijalankan ketika wadah mulai atau argumen untuk ENTRYPOINT jika ditentukan.

Ya, ini bercampur.

Anda dapat mengesampingkan salah satu dari mereka saat menjalankan buruh pelabuhan.

Perbedaan antara CMD dan ENTRYPOINT dengan contoh :

docker run -it --rm yourcontainer /bin/bash            <-- /bin/bash overrides CMD
                                                       <-- /bin/bash does not override ENTRYPOINT
docker run -it --rm --entrypoint ls yourcontainer      <-- overrides ENTRYPOINT with ls
docker run -it --rm --entrypoint ls yourcontainer  -la  <-- overrides ENTRYPOINT with ls and overrides CMD with -la

Lebih lanjut tentang perbedaan antara CMDdanENTRYPOINT :

Argumen untuk docker run seperti / bin / bash menimpa semua perintah CMD yang kami tulis di Dockerfile.

ENTRYPOINT tidak dapat diganti pada saat dijalankan dengan perintah normal seperti docker run [args]. Di argsakhir docker run [args]disediakan sebagai argumen untuk ENTRYPOINT. Dengan cara ini kita dapat membuat containeryang seperti biner normal sepertils .

Jadi CMD dapat bertindak sebagai parameter default untuk ENTRYPOINT dan kemudian kita dapat mengganti argumen CMD dari [args].

ENTRYPOINT dapat diganti dengan --entrypoint.


38

Pendeknya:

  • CMD menetapkan perintah dan / atau parameter default, yang dapat ditimpa dari baris perintah saat wadah buruh pelabuhan berjalan.
  • Perintah dan parameter ENTRYPOINT tidak akan ditimpa dari baris perintah. Sebagai gantinya, semua argumen baris perintah akan ditambahkan setelah parameter ENTRYPOINT.

Jika Anda memerlukan detail lebih lanjut atau ingin melihat perbedaan pada contoh, ada posting blog yang secara komprehensif membandingkan CMD dan ENTRYPOINT dengan banyak contoh - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/


21

Saya akan menambahkan jawaban saya sebagai contoh 1 yang mungkin membantu Anda lebih memahami perbedaannya.

Misalkan kita ingin membuat gambar yang akan selalu menjalankan perintah tidur ketika dimulai. Kami akan membuat gambar kami sendiri dan menentukan perintah baru:

FROM ubuntu
CMD sleep 10

Sekarang, kami membangun gambar:

docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits

Bagaimana jika kita ingin mengubah jumlah detik? Kita harus mengubah Dockerfilekarena nilainya hardcode di sana, atau menimpa perintah dengan memberikan yang berbeda:

docker run custom_sleep sleep 20

Meskipun ini berfungsi, ini bukan solusi yang baik, karena kami memiliki perintah "tidur" yang berlebihan (tujuan penampung adalah untuk tidur , jadi harus secara eksplisit menentukansleep perintah itu bukan praktik yang baik).

Sekarang mari kita coba menggunakan ENTRYPOINTinstruksi:

FROM ubuntu
ENTRYPOINT sleep

Instruksi ini menentukan program yang akan dijalankan ketika wadah mulai .

Sekarang kita dapat menjalankan:

docker run custom_sleep 20

Bagaimana dengan nilai default? Yah, Anda menebaknya dengan benar:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

Ini ENTRYPOINTadalah program yang akan dijalankan, dan nilai yang diteruskan ke wadah akan ditambahkan padanya.

The ENTRYPOINTdapat ditimpa dengan menentukan --entrypointbendera, diikuti oleh titik entri baru yang ingin Anda gunakan.

Bukan milik saya, saya pernah menonton tutorial yang memberikan contoh ini


1
Berikut ini tautan ke tutorial: youtu.be/OYbEWUbmk90 . Mungkin bermanfaat bagi pengguna di masa depan.
ChiPlusPlus


7

Komentar pada fungsi EntryPoint dalam kode

// ENTRYPOINT / usr / sbin / nginx.

// Tetapkan titik masuk (yang default ke sh -c) ke / usr / sbin / nginx.

// Akan menerima CMD sebagai argumen untuk / usr / sbin / nginx.

Referensi lain dari dokumen

Anda dapat menggunakan bentuk exec dari ENTRYPOINT untuk mengatur perintah dan argumen default yang cukup stabil dan kemudian menggunakan CMD untuk mengatur default tambahan yang lebih mungkin untuk diubah.

Contoh:

FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]

Build : sudo docker build -t ent_cmd.

CMD arguments are easy to override.

NO argument (sudo docker -it ent_cmd)                :  ping localhost 
argument    (sudo docker run -it ent_cmd google.com) :  ping google.com

.

To override EntryPoint argument, you need to supply entrypoint
sudo docker run -it --entrypoint="/bin/bash" ent_cmdd

ps: Di hadapan EntryPoint, CMD akan mengadakan argumen untuk diumpankan ke EntryPoint. Tidak adanya EntryPoint, CMD akan menjadi perintah yang akan dijalankan.


3

CMDperintah yang disebutkan di dalam Dockerfilefile dapat ditimpa melalui docker runperintah sementara ENTRYPOINTtidak bisa.


4
docker run --helpperintah mengatakan sebaliknya:--entrypoint string Overwrite the default ENTRYPOINT of the image
iomv

3

Saya telah membaca semua jawaban dan saya ingin meringkas untuk pemahaman yang lebih baik pada pandangan pertama seperti berikut:

Pertama, seluruh perintah yang dieksekusi dalam wadah mencakup dua bagian: perintah dan argumen

  • ENTRYPOINT mendefinisikan executable yang dipanggil ketika container dimulai (untuk perintah)

  • CMD menentukan argumen yang diteruskan ke ENTRYPOINT (untuk argumen)

Dalam buku Kubernetes In Action menunjukkan catatan penting tentang itu. (bab 7)

Meskipun Anda dapat menggunakan instruksi CMD untuk menentukan perintah yang ingin Anda jalankan ketika gambar dijalankan, cara yang benar adalah melakukannya melalui instruksi ENTRYPOINT dan hanya menentukan CMD jika Anda ingin mendefinisikan argumen default.

Anda juga dapat membaca artikel ini untuk penjelasan yang bagus dengan cara yang sederhana


2

CMD:

  • CMD ["executable","param1","param2"]: ["executable","param1","param2"]adalah proses pertama.
  • CMD command param1 param2: /bin/sh -c CMD command param1 param2adalah proses pertama.CMD command param1 param2bercabang dari proses pertama.
  • CMD ["param1","param2"]: Formulir ini digunakan untuk memberikan argumen default untuk ENTRYPOINT.

ENTRYPOINT (Daftar berikut ini tidak mempertimbangkan kasus di mana CMD dan ENTRYPOINT digunakan bersama-sama):

  • ENTRYPOINT ["executable", "param1", "param2"]: ["executable", "param1", "param2"]adalah proses pertama.
  • ENTRYPOINT command param1 param2: /bin/sh -c command param1 param2adalah proses pertama. command param1 param2bercabang dari proses pertama.

Seperti yang dikatakan creack , CMD dikembangkan terlebih dahulu. Kemudian ENTRYPOINT dikembangkan untuk penyesuaian lebih lanjut. Karena mereka tidak dirancang bersama, ada beberapa fungsi yang tumpang tindih antara CMD dan ENTRYPOINT, yang sering membingungkan orang.


2

Kebanyakan orang menjelaskannya dengan sempurna di sini, jadi saya tidak akan mengulangi semua jawaban. Tetapi untuk mendapatkan perasaan yang baik, saya akan menyarankan mengujinya sendiri dengan melihat proses dalam wadah.

Buat Dockerfile kecil dari formulir:

FROM ubuntu:latest
CMD /bin/bash

Bangun, jalankan dengan docker run -it theimagedan jalankan ps -eo ppid,pid,argsdalam wadah. Bandingkan output ini dengan output yang Anda terima dari ps saat menggunakan:

  • docker run -it theimage bash
  • Membangun kembali gambar tetapi dengan ENTRYPOINT /bin/bashdan menjalankannya dengan dua cara
  • Menggunakan CMD ["/bin/bash"]
  • ...

Dengan cara ini Anda akan dengan mudah melihat perbedaan antara semua metode yang mungkin untuk diri Anda sendiri.


0

Dokumentasi resmi praktik terbaik Dockerfile sangat membantu menjelaskan perbedaan. Dockerfile praktik terbaik

CMD:

Instruksi CMD harus digunakan untuk menjalankan perangkat lunak yang terkandung oleh gambar Anda, bersama dengan argumen apa pun. CMD harus hampir selalu digunakan dalam bentuk CMD ["executable", "param1", "param2"…]. Jadi, jika gambar tersebut untuk layanan, seperti Apache dan Rails, Anda akan menjalankan sesuatu sepertiCMD ["apache2","-DFOREGROUND"] . Memang, bentuk instruksi ini direkomendasikan untuk gambar berbasis layanan apa pun.

TITIK MASUK:

Penggunaan terbaik untuk ENTRYPOINT adalah mengatur perintah utama gambar, yang memungkinkan gambar itu dijalankan seolah-olah itu perintah itu (dan kemudian menggunakan CMD sebagai flag default).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.