Στο Dockerfiles υπάρχουν δύο εντολές που μου φαίνονται παρόμοιες: CMD
και ENTRYPOINT
. Αλλά υποθέτω ότι υπάρχει μια (λεπτή;) διαφορά μεταξύ τους - αλλιώς δεν θα είχε νόημα να υπάρχουν δύο εντολές για το ίδιο ακριβώς πράγμα.
Η τεκμηρίωση αναφέρει για την CMD
Ο κύριος σκοπός μιας CMD είναι να παρέχει προεπιλογές για έναν εκτελούμενο περιέκτη.
και για το ENTRYPOINT
:
Ένα ENTRYPOINT σας βοηθά να διαμορφώσετε ένα δοχείο που μπορείτε να εκτελέσετε ως εκτελέσιμο.
Ποια είναι λοιπόν η διαφορά μεταξύ αυτών των δύο εντολών;
Το Docker έχει ένα προεπιλεγμένο σημείο εισόδου που είναι το /bin/sh -c
αλλά δεν έχει μια προεπιλεγμένη εντολή.
Όταν εκτελείτε το docker ως εξής:
docker run -i -t ubuntu bash
το σημείο εισόδου είναι το προεπιλεγμένο /bin/sh -c
, η εικόνα είναι ubuntu
και η εντολή είναι bash
.
Η εντολή εκτελείται μέσω του σημείου εισόδου. δηλ. το πραγματικό πράγμα που εκτελείται είναι το /bin/sh -c bash
. Αυτό επέτρεψε στο Docker να υλοποιήσει το RUN
γρήγορα, βασιζόμενο στον αναλυτή του κελύφους's.
Αργότερα, οι άνθρωποι ζήτησαν να μπορούν να το προσαρμόσουν αυτό, οπότε εισήχθησαν τα ENTRYPOINT
και --entrypoint
.
Ό,τι ακολουθεί το ubuntu
στο παραπάνω παράδειγμα είναι η εντολή και περνάει στο σημείο εισόδου. Όταν χρησιμοποιείτε την εντολή CMD
, είναι ακριβώς σαν να κάνετε docker run -i -t ubuntu <cmd>
. Το <cmd>
θα είναι η παράμετρος του σημείου εισόδου.
Θα έχετε επίσης το ίδιο αποτέλεσμα αν αντί αυτού πληκτρολογήσετε αυτή την εντολή docker run -i -t ubuntu
. Θα εξακολουθήσετε να ξεκινάτε ένα κέλυφος bash στο δοχείο, επειδή το ubuntu Dockerfile καθόρισε ένα προεπιλεγμένο CMD: CMD ["bash"]
Καθώς όλα περνούν στο σημείο εισόδου, μπορείτε να έχετε μια πολύ ωραία συμπεριφορά από τις εικόνες σας. Το παράδειγμα του @Jiri είναι καλό, δείχνει πώς να χρησιμοποιήσετε μια εικόνα ως "δυαδικό". Όταν χρησιμοποιείτε το ["/bin/cat"]
ως σημείο εισόδου και στη συνέχεια κάνετε docker run img /etc/passwd
, το καταλαβαίνετε, το /etc/passwd
είναι η εντολή και περνάει στο σημείο εισόδου, οπότε η εκτέλεση του τελικού αποτελέσματος είναι απλά /bin/cat /etc/passwd
.
Ένα άλλο παράδειγμα θα ήταν να έχετε οποιοδήποτε cli ως σημείο εισόδου. Για παράδειγμα, αν έχετε μια εικόνα redis, αντί να εκτελέσετε docker run redisimg redis -H κάτι -u toto get key
, μπορείτε απλά να έχετε ENTRYPOINT ["redis", "-H", "κάτι", "-u", "toto"]
και στη συνέχεια να εκτελέσετε έτσι για το ίδιο αποτέλεσμα: docker run redisimg get key
.
Το ENTRYPOINT
καθορίζει μια εντολή που θα εκτελείται πάντα κατά την εκκίνηση του δοχείου.
Το CMD
καθορίζει τα ορίσματα που θα τροφοδοτούνται στο ENTRYPOINT
.
Αν θέλετε να κάνετε μια εικόνα αφιερωμένη σε μια συγκεκριμένη εντολή θα χρησιμοποιήσετε ENTRYPOINT ["/path/dedicated_command"]
Διαφορετικά, αν θέλετε να φτιάξετε ένα image για γενική χρήση, μπορείτε να αφήσετε το ENTRYPOINT
χωρίς προσδιορισμό και να χρησιμοποιήσετε το CMD ["/path/dedicated_command"]
καθώς θα μπορείτε να παρακάμψετε τη ρύθμιση παρέχοντας ορίσματα στο docker run
.
Για παράδειγμα, αν το αρχείο Docker σας είναι: "Dockerfile":
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
Η εκτέλεση της εικόνας χωρίς κανένα όρισμα θα κάνει ping στο 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
Τώρα, η εκτέλεση της εικόνας με ένα όρισμα θα κάνει ping το όρισμα:
$ 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
Για σύγκριση, αν το αρχείο Docker είναι:
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
Η εκτέλεση της εικόνας χωρίς κανένα όρισμα θα κάνει ping στο 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
Αλλά η εκτέλεση της εικόνας με κάποιο όρισμα θα εκτελέσει το όρισμα:
docker run -it test bash
root@e8bb7249b843:/#
Δείτε αυτό το άρθρο από τον Brian DeHamer για ακόμα περισσότερες λεπτομέρειες: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
Ναι, αυτή είναι μια καλή ερώτηση. Δεν το καταλαβαίνω πλήρως ακόμα, αλλά:
Καταλαβαίνω ότι το ENTRYPOINT
είναι το δυαδικό αρχείο που εκτελείται. Μπορείτε να παρακάμψετε το σημείο εισόδου με --entrypoint="".
docker run -t -i --entrypoint="/bin/bash" ubuntu
Το CMD είναι το προεπιλεγμένο όρισμα για το container. Χωρίς entrypoint, το προεπιλεγμένο όρισμα είναι η εντολή που εκτελείται. Με σημείο εισόδου, το cmd περνάει στο σημείο εισόδου ως όρισμα. Μπορείτε να εξομοιώσετε μια εντολή με entrypoint.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Έτσι, το κύριο πλεονέκτημα είναι ότι με το entrypoint μπορείτε να περάσετε ορίσματα (cmd) στο δοχείο σας. Για να το πετύχετε αυτό, πρέπει να χρησιμοποιήσετε και τα δύο:
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
και
docker build -t=cat .
τότε μπορείτε να χρησιμοποιήσετε:
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT