Tại sao tôi không thể sử dụng Docker CMD nhiều lần để chạy nhiều dịch vụ?


96

Tôi đã xây dựng một hình ảnh cơ sở từ Dockerfile có tên centos + ssh. Trong Dockerfile của centos + ssh, tôi sử dụng CMD để chạy dịch vụ ssh.

Sau đó, tôi muốn xây dựng một hình ảnh chạy dịch vụ khác có tên là Rabbitmq, Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Để bắt đầu container Rabbitmq, hãy chạy :

docker run -d -p 222:22 -p 4149:4149 rabbitmq

nhưng dịch vụ ssh không hoạt động, có nghĩa là Dockerfile CMD của Rabbitmq ghi đè CMD của centos.

  1. CMD hoạt động như thế nào bên trong hình ảnh docker?
  2. Nếu tôi muốn chạy nhiều dịch vụ, làm thế nào để? Sử dụng giám sát viên?

Câu trả lời:


62

Mặc dù CMD được viết ra trong Dockerfile, nó thực sự là thông tin thời gian chạy. Cũng giống như EXPOSE, nhưng trái ngược với ví dụ: RUN và ADD. Bởi điều này, ý tôi là bạn có thể ghi đè nó sau này, trong Dockerfile mở rộng hoặc đơn giản trong lệnh chạy của bạn, đó là những gì bạn đang gặp phải. Tại mọi thời điểm, chỉ có thể có một CMD.

Nếu bạn muốn chạy nhiều dịch vụ, tôi thực sự sẽ sử dụng trình giám sát. Bạn có thể tạo tệp cấu hình người giám sát cho từng dịch vụ, THÊM chúng vào một thư mục và chạy trình giám sát supervisord -c /etc/supervisorđể trỏ đến tệp cấu hình người giám sát tải tất cả các dịch vụ của bạn và trông giống như

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Nếu bạn muốn biết thêm chi tiết, tôi đã viết một blog về chủ đề này tại đây: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- di sản/


Cảm ơn, người giám sát là một ý kiến ​​hay, nhưng tôi không biết CMD hoạt động như thế nào bên trong hình ảnh
docker

2
Bạn đã hỏi hai câu hỏi, 2. về việc chạy nhiều dịch vụ. Nếu bạn thắc mắc về cách thức hoạt động của CMD, vui lòng giải thích cụ thể những gì bạn muốn biết. Tôi đã đề cập rằng nó là thông tin thời gian chạy và bị ghi đè bởi bất kỳ CMD mới nào.
qkrijger

118

Bạn nói đúng, Dockerfile thứ hai sẽ ghi đè lên CMDlệnh của cái đầu tiên. Docker sẽ luôn chạy một lệnh duy nhất, không chạy nhiều hơn. Vì vậy, ở cuối Dockerfile của bạn, bạn có thể chỉ định một lệnh để chạy. Không hơn.

Nhưng bạn có thể thực hiện cả hai lệnh trong một dòng:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

Bạn cũng có thể làm gì để làm cho Dockerfile của mình gọn gàng hơn một chút, bạn có thể đặt các lệnh CMD của mình vào một tệp bổ sung:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

Và một tệp như thế này:

service sshd start &
/opt/mq/sbin/rabbitmq-server start

1
cảm ơn, tôi nghĩ sử dụng trình giám sát là tốt hơn. nhưng tại sao docker chỉ chạy một CMD? Điều gì xảy ra bên trong?
edwardsbean

1
Tôi không biết những gì đang xảy ra bên trong. Nhưng tôi nghĩ nó chỉ được thiết kế như vậy. Khi bạn có một hình ảnh và chạy một lệnh trong đó (ví dụ: với CMD), nó sẽ bắt đầu một vùng chứa. Vùng chứa chạy miễn là lệnh chạy. Và ngay sau khi lệnh kết thúc, vùng chứa cũng dừng lại. Vì vậy, mỗi vùng chứa đại diện cho một lệnh (đang chạy) duy nhất.
Thomas Uhrig

tôi nghĩ có thể do lcx hoặc giới hạn của cái gì đó
edwardsbean

2
@ Tyguy7 .. ................?
StartupGuy

1
&&kỹ thuật sẽ chỉ hoạt động với các dịch vụ không tương tác (có thể bắt đầu ở chế độ nền) nếu không, chỉ dịch vụ đầu tiên sẽ chạy.
noraj

26

Trong khi tôi tôn trọng câu trả lời từ qkrijger giải thích cách bạn có thể giải quyết vấn đề này, tôi nghĩ rằng chúng ta có thể tìm hiểu thêm nhiều điều về những gì đang xảy ra ở đây ...

Để thực sự trả lời câu hỏi của bạn về " tại sao " ... Tôi nghĩ sẽ hữu ích cho bạn khi hiểu cách docker stophoạt động của lệnh và tất cả các quy trình phải được tắt sạch để ngăn chặn sự cố khi bạn cố gắng khởi động lại chúng (hỏng tệp, v.v.).

Vấn đề: Điều gì sẽ xảy ra nếu docker đã khởi động SSH từ lệnh của nó khởi động RabbitMQ từ tệp Docker của bạn? " Lệnh dừng của docker cố gắng dừng một vùng chứa đang chạy trước tiên bằng cách gửi tín hiệu SIGTERM đến quy trình gốc (PID 1) trong vùng chứa. " Quá trình nào đang theo dõi docker là PID 1 sẽ nhận được SIGTERM? Nó sẽ là SSH hay Rabbit ?? "Theo mô hình quy trình Unix, quy trình init - PID 1 - kế thừa tất cả các quy trình con mồ côi và phải khai thác chúng. Hầu hết các vùng chứa Docker không có quy trình init thực hiện điều này một cách chính xác và kết quả là các vùng chứa của chúng bị lấp đầy quá trình zombie theo thời gian. "

Trả lời: Docker chỉ đơn giản là mất rằng CMD cuối cùng là một trong đó sẽ được đưa ra như là quá trình gốc với PID 1 và nhận được SIGTERM từ docker stop.

Giải pháp được đề xuất: Bạn nên sử dụng (hoặc tạo) một hình ảnh cơ sở được tạo riêng để chạy nhiều hơn một dịch vụ, chẳng hạn như phusion / baseimage

Cần lưu ý rằng tini tồn tại chính xác vì lý do này và kể từ Docker 1.13 trở lên, tini chính thức là một phần của Docker, điều này cho chúng ta biết rằng việc chạy nhiều hơn một quy trình trong Docker LÀ HỢP LỆ .. vì vậy ngay cả khi ai đó tuyên bố có kỹ năng hơn về Docker, và khẳng định rằng bạn thật ngớ ngẩn khi nghĩ đến việc làm này, hãy biết rằng bạn không phải vậy. Có những tình huống hoàn toàn hợp lệ để làm như vậy.

Điều cần biết:


3

Câu trả lời chính thức của docker cho Chạy nhiều dịch vụ trong một vùng chứa .

Nó giải thích cách bạn có thể làm điều đó với hệ thống init (systemd, sysvinit, mới bắt đầu), script ( CMD ./my_wrapper_script.sh) hoặc một trình giám sát như thế nào supervisord.

Giải &&pháp thay thế chỉ có thể hoạt động đối với các dịch vụ khởi động ở chế độ nền (daemon) hoặc sẽ thực thi nhanh chóng mà không cần tương tác và đưa ra lời nhắc. Thực hiện điều này với một dịch vụ tương tác (giữ lời nhắc) và chỉ dịch vụ đầu tiên sẽ bắt đầu.


0

Để giải quyết lý do tại sao CMD được thiết kế để chỉ chạy một dịch vụ cho mỗi vùng chứa, chúng ta hãy nhận ra điều gì sẽ xảy ra nếu các máy chủ phụ chạy trong cùng một vùng chứa không phải là tầm thường / phụ trợ mà là "chính" (ví dụ: bộ nhớ đi kèm với ứng dụng giao diện người dùng). Đối với người mới bắt đầu, nó sẽ chia nhỏ một số tính năng chứa quan trọng như chia tỷ lệ theo chiều ngang (tự động) và lập lịch lại giữa các nút, cả hai đều giả định chỉ có một ứng dụng (nguồn tải CPU) trên mỗi vùng chứa. Sau đó, có vấn đề về lỗ hổng - nhiều máy chủ bị lộ trong một vùng chứa đồng nghĩa với việc vá các CVE thường xuyên hơn ...

Vì vậy, hãy thừa nhận rằng đó là một 'thúc đẩy' từ các nhà thiết kế Docker (và Kubernetes / Openshift) hướng tới các phương pháp hay và chúng ta không nên phát minh lại các cách giải quyết (SSH là không cần thiết - chúng tôi đã docker exec / kubectl exec / oc rshthiết kế để thay thế nó).

  • Thêm thông tin

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

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.