Làm thế nào để tự động bắt đầu một dịch vụ khi chạy một container docker?


157

Tôi có Dockerfile để cài đặt máy chủ MySQL trong một thùng chứa, sau đó tôi bắt đầu như thế này:

sudo docker run -t -i 09d18b9a12be /bin/bash

Nhưng dịch vụ MySQL không tự động khởi động, tôi phải chạy thủ công (từ trong container):

service mysql start

Làm cách nào để tự động khởi động dịch vụ MySQL khi tôi chạy bộ chứa docker?


1
không, đối với một dịch vụ đơn giản, người giám sát là không cần thiết, nó gây phức tạp cho người dùng bắt đầu
Larry Cai

8
bạn có thể muốn sao chép dockerfile tại đây thay vì liên kết đến một tệp không còn tồn tại
neo112

Bài viết về dockerord trên giám sát hiện có tại đây: docs.docker.com/config/containers/multi-service_container Tôi đã sử dụng lệnh && tail để dịch vụ của tôi hoạt động - nhưng cần thêm "--cap-add SYS_PTRACE" vào docker chạy lệnh.
Ted Cahall

Câu trả lời:


205

Đầu tiên, có một vấn đề trong bạn Dockerfile:

RUN service mysql restart && /tmp/setup.sh

Hình ảnh Docker không lưu các quy trình đang chạy. Do đó, RUNlệnh của bạn chỉ thực thi trong docker buildgiai đoạn và dừng sau khi quá trình xây dựng hoàn thành. Thay vào đó, bạn cần chỉ định lệnh khi container được bắt đầu bằng cách sử dụng các lệnh CMDhoặc ENTRYPOINTnhư dưới đây:

CMD mysql start

Thứ hai, container docker cần một tiến trình (lệnh cuối cùng) để tiếp tục chạy, nếu không container sẽ thoát / dừng. Do đó, service mysql startlệnh bình thường không thể được sử dụng trực tiếp trong Dockerfile.

Giải pháp

Có ba cách điển hình để duy trì quá trình chạy:

  • Sử dụng servicelệnh và nối thêm lệnh không kết thúc sau đó như thếtail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

Điều này thường được ưa thích khi bạn có một dịch vụ duy nhất đang chạy vì nó làm cho nhật ký xuất ra có thể truy cập vào docker.

  • Hoặc sử dụng lệnh foreground để làm điều này

    CMD /usr/bin/mysqld_safe
    

Điều này chỉ hoạt động nếu có một kịch bản như thế mysqld_safe.

  • Hoặc gói các tập lệnh của bạn vào start.shvà đặt nó vào cuối

    CMD /start.sh
    

Điều này là tốt nhất nếu lệnh phải thực hiện một loạt các bước, một lần nữa, /start.shnên tiếp tục chạy.

Ghi chú

Đối với người mới bắt đầu sử dụng supervisordkhông được khuyến khích. Thành thật mà nói, nó là quá mức cần thiết. Sẽ tốt hơn nhiều khi sử dụng dịch vụ đơn / lệnh đơn cho container.

BTW: vui lòng kiểm tra https://registry.hub.docker.com để biết hình ảnh docker mysql hiện có để tham khảo


Làm thế nào bạn sẽ khởi động lại dịch vụ một khi đã bắt đầu trong container docker?
K - Độc tính trong SO đang tăng lên.

3
@KarlMorrisondocker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
kaiser

1
Tôi không khuyên bạn nên theo dõi nhật ký lỗi của MySQL để xác định xem cơ sở dữ liệu có đang chạy hay không. Trong hầu hết các thiết lập mysqld, máy chủ sẽ khôi phục từ các lỗi soe và trong quá trình thực hiện việc này, nhật ký lỗi sẽ bị đóng và sau đó mở lại. Tôi cũng không chắc chắn rằng đuôi của bạn -F sẽ phù hợp với bạn trong tất cả hoặc thậm chí một số trường hợp.
Brian Aker

Tôi không chắc tại sao, nhưng tùy chọn giải pháp đầu tiên hoạt động tốt cho tập lệnh dịch vụ. Khi bạn không sử dụng đuôi, nó sẽ thất bại, ngay cả khi dịch vụ được bắt đầu (ít nhất là đối với dịch vụ tomcat7). Với đuôi nó hoạt động. Đối với cả hai trường hợp, bạn cần sử dụng chuyển đổi cap_add (- cap-add SYS_PTRACE để chạy) với ít nhất SYS_PTRACE
zhrist


73

Trong của bạn Dockerfile, thêm ở dòng cuối cùng

ENTRYPOINT service ssh restart && bash

Nó làm việc cho tôi

Và đây là kết quả:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running

2
Điều này là tốt nhưng tôi nghĩ rằng bạn không thể có một container tách ra theo cách này.
mdob

1
Nó hiệu quả tuyệt vời đối với tôi. Tôi gặp sự cố khi đưa Nginx 1.8 tự động khởi động. Bạn có thể thấy việc thêm hữu ích sau: RUN echo "daemon off;" >> /etc/nginx/nginx.conf RUN ln -sf / dev / stdout /var/log/nginx/access.log RUN ln -sf / dev / stderr /var/log/nginx/error.log
Lionel Morrison

1
Có bất kỳ nhược điểm nào đối với giải pháp này không?
srph

2
Bắt đầu Bash cuối cùng là một ý tưởng tồi khi bạn muốn dừng dịch vụ của mình một cách duyên dáng, bởi vì theo cách này, docker contaienr không thể bị chặn docker stophoặc docker restartduyên dáng, chỉ cần nó có thể bị giết.
Mohammed Noureldin

Tôi đã làm việc trên trình đóng gói để tạo hình ảnh docker và điều này dường như khắc phục vấn đề của tôi với conaitner trong tệp packer. "thay đổi": ["Dịch vụ ENTRYPOINT nginx bắt đầu && / bin / bash"]
karthik101

8

Đơn giản! Thêm vào cuối dockerfile:

ENTRYPOINT service mysql start && /bin/bash

Đây là câu trả lời tốt nhất giải quyết vấn đề Docker Container hiện tại của tôi : Docker version 18.09.7, build 2d0083d, không có && /bin/bashdịch vụ sẽ dừng ngay lập tức
Dài

7

Có một cách khác để làm điều đó mà tôi luôn thấy dễ đọc hơn.

Giả sử bạn muốn bắt đầu rabbitmq và mongodb khi bạn chạy nó thì bạn CMDsẽ trông giống như thế này:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

Vì bạn chỉ có thể có một mẹo CMDcho mỗi Dockerfilemẹo là nối tất cả các hướng dẫn &&và sau đó sử dụng \cho mỗi lệnh để bắt đầu một dòng mới.

Nếu bạn kết thúc việc thêm vào nhiều trong số đó, tôi khuyên bạn nên đặt tất cả các lệnh của mình vào tệp tập lệnh và khởi động nó như @ larry-cai đề xuất:

CMD /start.sh

3

Trong trường hợp của tôi, tôi có một ứng dụng web PHP đang được Apache2 phục vụ trong bộ chứa docker kết nối với cơ sở dữ liệu phụ trợ MYSQL. Giải pháp của Larry Cai đã làm việc với những sửa đổi nhỏ. Tôi đã tạo một entrypoint.shtệp trong đó tôi đang quản lý các dịch vụ của mình. Tôi nghĩ rằng việc tạo một entrypoint.shkhi bạn có nhiều hơn một lệnh để thực thi khi container của bạn khởi động là một cách sạch hơn để bootstrap docker.

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi

Chỉ cần đặt nó cùng với Dockerfile của bạn. Sau đó, trong Dockerfile của bạn, bạn sẽ có một hướng dẫn sao chép tệp này vào vị trí mong muốn. Sau đó, bạn trỏ ENTRYPOINT ['your location']hướng dẫn đến tập tin kịch bản. Hãy nhớ đặt quyền thực thi trên tập lệnh của bạn mặc dù. COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]. Trong ví dụ này, tôi đã sao chép điểm vào của tôi vào thư mục gốc trong thùng chứa docker.
Ông Doomsbuster

Dockerfile ở đâu?
Viktor Joras

3

Tôi có cùng một vấn đề khi tôi muốn tự động bắt đầu dịch vụ ssh. Tôi thấy rằng nối thêm

/etc/init.d/ssh bắt đầu
đến
~ / .bashrc
có thể giải quyết nó, nhưng chỉ có bạn mở nó với bash sẽ làm.


1

Tôi thêm mã sau vào /root/.bashrc để chỉ chạy mã một lần,

Vui lòng cam kết container với hình ảnh trước khi chạy tập lệnh này, nếu không, tệp 'docker_service' sẽ được tạo trong hình ảnh và không có dịch vụ nào sẽ được chạy.

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi

1

Đây là cách tôi tự động khởi động dịch vụ MySQL bất cứ khi nào container docker chạy.

Trong trường hợp của tôi, tôi cần chạy không chỉ MySQL mà cả PHP, Nginx và Memcached

Tôi có các dòng sau trong Dockerfile

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

Thêm && bash sẽ giữ cho Nginx, MySQL, PHP và Memcached chạy trong vùng chứa.


1

Điều này không hoạt động CMD service mysql start && /bin/bash

Điều này không hoạt động CMD service mysql start ; /bin/bash ;

- tôi đoán chế độ tương tác sẽ không hỗ trợ tiền cảnh.

Những công việc này !! CMD service nginx start ; while true ; do sleep 100; done;

Những công việc này !! CMD service nginx start && tail -F /var/log/nginx/access.log

hãy cẩn thận bạn nên sử dụng docker run -p 80:80 nginx_bashmà không cần tham số lệnh.


0

Tài liệu sau đây từ trang web Docker cho thấy cách triển khai dịch vụ SSH trong thùng chứa docker. Nó có thể dễ dàng thích ứng với dịch vụ của bạn:

Một biến thể cho câu hỏi này cũng đã được hỏi ở đây:


công cụ nsenter là một cách tiếp cận khác để nhập vào một container, mà không yêu cầu cài đặt máy chủ SSH: github.com/jpetazzo/nsenter . Nhưng phương pháp này yêu cầu quyền truy cập vào máy chủ Docker của bạn (thông thường truy cập SSH là đủ).
Fabien Balageas

Liên kết docs.docker.com/sdvisor/#/examples/rasty_ssh_service không hoạt động. Bạn có thể vui lòng cập nhật nó?
Ankur

0
docker export -o <nameOfContainer>.tar <nameOfContainer>

Có thể cần phải cắt tỉa container hiện có bằng cách sử dụng docker prune ...

Nhập khẩu với các sửa đổi cần thiết:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

Chạy container chẳng hạn với tùy chọn luôn khởi động lại để đảm bảo nó sẽ tự động tiếp tục sau khi tái chế máy chủ / daemon:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

Lưu ý bên lề: Theo tôi hợp lý là chỉ bắt đầu dịch vụ cron rời khỏi container càng tốt càng tốt sau đó chỉ cần sửa đổi crontab hoặc cron.hourly, .daily v.v ... với các kịch bản kiểm tra / giám sát tương ứng. Lý do là Bạn chỉ dựa vào một trình nền và trong trường hợp thay đổi, việc tìm lại hoặc phân phối lại các tập lệnh cron thay vì các dịch vụ theo dõi bắt đầu khi khởi động sẽ dễ dàng hơn.

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.