Beberapa perintah dalam Docker cmd direktif

Tidak memahami apa yang terjadi ketika saya mencoba menjalankan dua perintah saat runtime melalui arahan CMD di `Dockerfile. Saya berasumsi bahwa ini harus bekerja:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Tapi itu tidak bekerja. Kontainer belum dimulai. Jadi saya harus melakukannya seperti ini:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Aku tidak mengerti. Kenapa begitu? Mengapa baris pertama bukan cara yang benar? Dapatkah seseorang menjelaskan kepada saya hal-hal" format shell CMD vs format JSON, dll " ini. Dengan kata sederhana.

Hanya untuk dicatat - sama dengan command: direktif dalam docker-compose.yml, seperti yang diharapkan.

Saya percaya perbedaannya mungkin karena perintah kedua melakukan pemrosesan shell sedangkan yang pertama tidak. Per dokumentasi resmi, ada exec dan shell formulir. Perintah pertama Anda adalah exec bentuk. The exec bentuk tidak memperluas variabel lingkungan sementara shell bentuk tidak. Ada kemungkinan bahwa dengan menggunakan exec bentuk perintah gagal karena ketergantungannya pada pemrosesan shell. Anda dapat memeriksa ini dengan menjalankan docker logs CONTAINERID

Perintah kedua Anda, bentuk shell, setara dengan -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Kutipan dari dokumentasi -

Catatan: tidak seperti bentuk shell, bentuk exec tidak memanggil shell perintah. Ini berarti bahwa pemrosesan shell normal tidak terjadi. Misalnya, CMD [ "echo", "$HOME" ] tidak akan melakukan substitusi variabel pada $HOME. Jika Anda ingin pemrosesan shell maka gunakan formulir shell atau jalankan shell secara langsung, misalnya: CMD [ "sh", "-c", "echo", "$HOME" ].

Jangan membuat sulit pada diri sendiri. Hanya membuat file bash " start. sh & quot;:

#!/bin/bash/usr/bin/command2 param1/usr/bin/command1

dalam Dockerfile Anda lakukan:

ADD start.sh /RUN chmod +x /start.shCMD ["/start.sh"]

Sintaks json dari CMD (dan RUN dan ENTRYPOINT) meneruskan argumen ke kernel secara langsung sebagai Exec syscall. Tidak ada pemisahan perintah dari argumen dengan spasi, pelolosan tanda kutip, pengalihan IO, substitusi variabel, perpipaan antar perintah, menjalankan banyak perintah, dll, di Exec syscall. Syscall hanya membutuhkan executable untuk dijalankan dan daftar argumen untuk diteruskan ke executable itu, dan menjalankannya.

Karakter seperti $ untuk memperluas variabel, ; untuk memisahkan perintah, (spasi) untuk memisahkan argumen, && dan || untuk perintah rantai, > untuk pengalihan keluaran, | untuk pipa antara perintah, dll, semua fitur dari shell dan perlu sesuatu seperti /bin/sh atau /bin/bash untuk menafsirkan dan mengimplementasikannya.


Jika Anda beralih ke sintaks string CMD, docker akan menjalankan perintah Anda dengan shell:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Jika tidak, sintaks kedua anda melakukan hal yang sama persis:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Perhatikan bahwa saya tidak menyarankan menjalankan beberapa perintah dengan cara ini di dalam wadah karena tidak ada penanganan kesalahan jika perintah pertama Anda gagal, terutama jika berjalan di latar belakang. Anda juga membiarkan shell berjalan sebagai pid 1 di dalam wadah yang akan merusak penanganan sinyal, menghasilkan penundaan 10 detik dan pembunuhan kontainer Anda yang tidak menyenangkan oleh buruh pelabuhan. Penanganan sinyal dapat dikurangi dengan menggunakan shell exec perintah:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

Namun, menangani proses yang gagal secara diam-diam di latar belakang mengharuskan Anda beralih ke semacam manajer multi-proses seperti supervisord, atau lebih disukai memecah aplikasi Anda menjadi beberapa wadah dan menerapkannya dengan sesuatu seperti docker-compose.

Saya kira perintah pertama gagal karena dalam bentuk CMD DOCKER, hanya parameter pertama yang dieksekusi, sisanya dimasukkan ke dalam perintah ini.

Bentuk kedua berfungsi karena semua perintah dipisahkan dengan"; " dimasukkan ke dalam perintah sh, yang mengeksekusinya.

Misalnya, bayangkan Anda memiliki dua perintah python untuk dijalankan python init_reset.py dan python app.py. Kemudian menggunakan CMD, Anda dapat menggabungkan dua perintah dengan perintah tunggal

CMD python init_reset.py ; python app.py

Dalam Docker compose, ini dapat dilakukan sebagai contoh berikut:

command: ["sh", "-c", "    apt update && apt install -y libldap-common;    cp /ca.crt /usr/local/share/ca-certificates/;    update-ca-certificates;    exec apache2-foreground  "]

The exec akan beralih konteks executable utama untuk apache2-forground.

Saya tidak berpikir Anda harus meletakkan setengah koma setelah "mulai"

alih-alih menggunakan

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

coba

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

karena docker menggunakan" sh-c", perintah di atas akan dijalankan seperti di bawah ini

/etc/init.d/nullmailer start/etc/init.d/nullmailer /usr/sbin/php5-fpm