Nhiều lệnh trong lệnh Docker CMD


39

Không hiểu chuyện gì đang xảy ra khi tôi cố gắng thực hiện hai lệnh trong thời gian chạy thông qua chỉ thị CMD trong `Dockerfile. Tôi giả định rằng điều này sẽ làm việc:

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

Nhưng nó không hoạt động. Container chưa bắt đầu. Vì vậy, tôi đã phải làm điều đó như thế này:

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

Tôi không hiểu Tại sao vậy? Tại sao dòng đầu tiên không đúng cách? Ai đó có thể giải thích cho tôi những thứ "định dạng shell CMD so với định dạng JSON, v.v." không. Nói một cách đơn giản.

Chỉ cần lưu ý - tương tự là với command:chỉ thị trong docker-compose.yml, như mong đợi.

Câu trả lời:


33

Tôi tin rằng sự khác biệt có thể phải làm với, lệnh thứ hai thực hiện xử lý shell, trong khi lệnh thứ nhất thì không. Theo tài liệu chính thức , có execshellbiểu mẫu, lệnh đầu tiên của bạn là biểu mẫu thực thi và nó không ví dụ mở rộng các biến môi trường, trong khi lệnh thứ hai thì có. Vì vậy, có thể, bằng cách sử dụng biểu mẫu exec, lệnh có thể bị lỗi do phụ thuộc vào xử lý shell. Bạn có thể kiểm tra điều này bằng cách chạydocker logs CONTAINERID

Lệnh thứ hai của bạn, dạng shell, tương đương với -

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

Đoạn trích từ tài liệu -

Lưu ý: Không giống như biểu mẫu shell, biểu mẫu exec không gọi shell shell. Điều này có nghĩa là xử lý vỏ bình thường không xảy ra. Ví dụ, CMD [ "echo", "$HOME" ]sẽ không thay thế trên $HOME. Nếu bạn muốn xử lý shell thì sử dụng biểu mẫu shell hoặc thực thi trực tiếp shell, ví dụ : CMD [ "sh", "-c", "echo", "$HOME" ].


Có lẽ lệnh thất bại vì các biến môi trường. Tôi vẫn nên sử dụng exechình thức này , vì nó là hình thức ưa thích? Tại sao nó được ưa thích? Hoặc tôi nên sử dụng shellhình thức đơn giản hơn ?
Vladan

Nó thất bại vì thực thi một lệnh sau một lệnh khác là hàm shell. Biến môi trường là một cá trích đỏ.
Bryan

Nếu bạn đang chạy nhiều dịch vụ trong Docker, tôi khuyên bạn nên sử dụng trình quản lý quy trình như người giám sát. Bằng cách đó, bạn chỉ khởi chạy giám sát trong phần CMD và nó sẽ đảm nhiệm việc bắt đầu các dịch vụ. Bạn có thể kiểm tra chi tiết tại đây - docs.docker.com/articles/USE_supervisord
Daniel t.

Đây là một bài viết chính xác tôi vừa đọc :) Cảm ơn.
Vladan

Tôi vẫn không hiểu tại sao bạn cần phải làm CMD [ "sh", "-c", "echo", "$HOME"]. Tại sao không CMD ["sh", "-c", "echo $HOME"]hoặc, cho vấn đề đó , CMD ["sh -c echo $HOME"]?
Sixty4bit

4

Đừng làm khó chính mình. Chỉ cần tạo một tệp bash "start.sh":

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/commnad1

trong Dockerfile của bạn làm:

ADD start.sh /

CMD ["/start.sh"]

2

Cú pháp JSON của CMD(và RUNENTRYPOINT) vượt qua các đối số hạt nhân trực tiếp như một syscall exec. Không có sự tách biệt lệnh với các đối số bằng khoảng trắng, thoát dấu ngoặc kép, chuyển hướng IO, thay thế biến đổi, đường ống giữa các lệnh, chạy nhiều lệnh, v.v., trong tòa nhà thực thi. Tòa nhà chỉ có thể thực thi để chạy và liệt kê các đối số để truyền cho thực thi đó và nó chạy nó.

Các ký tự muốn $mở rộng các biến, ;tách các lệnh, (dấu cách) để phân tách các đối số &&||để chuỗi lệnh, >để chuyển hướng đầu ra, chuyển đổi |giữa các lệnh, v.v., là tất cả các tính năng của trình bao và cần một cái gì đó giống như /bin/shhoặc /bin/bashđể diễn giải và thực hiện chúng.


Nếu bạn chuyển sang cú pháp chuỗi của CMD, docker sẽ chạy lệnh của bạn bằng shell:

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

Mặt khác, cú pháp thứ hai của bạn thực hiện chính xác điều tương tự:

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

Lưu ý rằng tôi không khuyên bạn nên chạy nhiều lệnh theo cách này bên trong một container vì không có xử lý lỗi nếu lệnh đầu tiên của bạn không thành công, đặc biệt là nếu nó chạy trong nền. Bạn cũng để một lớp vỏ chạy dưới dạng 1 trong hộp chứa, điều này sẽ phá vỡ việc xử lý tín hiệu, dẫn đến độ trễ 10 giây và giết chết container của bạn bằng docker. Việc xử lý tín hiệu có thể được giảm thiểu bằng cách sử dụng execlệnh shell :

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

Tuy nhiên, việc xử lý các quá trình âm thầm không thành công trong nền đòi hỏi bạn phải chuyển sang một loại trình quản lý đa quy trình như giám sát viên, hoặc tốt nhất là chia ứng dụng của bạn thành nhiều thùng chứa và triển khai chúng với thứ gì đó như docker-compose.


1

Tôi đoán lệnh đầu tiên thất bại vì ở dạng DOCKER CMD, chỉ tham số đầu tiên được thực thi, phần còn lại được đưa vào lệnh này.

Dạng thứ hai hoạt động vì tất cả các lệnh được phân tách bằng ";" được đưa vào lệnh sh, thực thi chúng.


1

Tôi không nghĩ bạn nên đặt dấu phẩy sau khi "bắt đầu"

thay vì sử dụng

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

thử

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

vì docker sử dụng "sh -c", lệnh trên sẽ được thực thi như bên dưới

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

Cú pháp json không chạy các lệnh với shell, không có sh -ctrong kịch bản đó.
BMitch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.