Bagaimana cara menjaga wadah Docker berjalan setelah memulai layanan?

155

Saya telah melihat banyak tutorial yang tampaknya melakukan hal yang sama yang saya coba lakukan, tetapi untuk beberapa alasan wadah Docker saya keluar. Pada dasarnya, saya membuat server web dan beberapa daemon di dalam wadah Docker. Saya melakukan bagian terakhir dari ini melalui skrip bash yang disebut run-all.shbahwa saya menjalankan melalui CMD di Dockerfile saya. run-all.shterlihat seperti ini:

service supervisor start
service nginx start

Dan saya memulainya di dalam Dockerfile saya sebagai berikut:

CMD ["sh", "/root/credentialize_and_run.sh"]

Saya dapat melihat bahwa semua layanan memulai dengan benar ketika saya menjalankan sesuatu secara manual (yaitu melanjutkan ke gambar dengan -i -t / bin / bash), dan semuanya terlihat berjalan dengan benar ketika saya menjalankan gambar, tetapi keluar sekali selesai memulai proses saya. Saya ingin proses berjalan tanpa batas, dan sejauh yang saya mengerti, wadah harus terus berjalan agar ini terjadi. Namun demikian, ketika saya berlari docker ps -a, saya melihat:

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        grave_jones

Apa yang menyebabkannya? Mengapa keluar? Saya tahu saya bisa meletakkan loop sementara di akhir skrip bash saya untuk mempertahankannya, tetapi apa cara yang benar untuk mencegahnya keluar?

Eli
sumber
1
apakah Anda mengekspos port layanan ke luar (opsi -p untuk menjalankan docker)? (tentu saja ini tidak akan mencegah mereka untuk keluar)
ribamar
1
Saya menggunakan ENTRYPOINT di Dockerfile saya, dan setelah skrip didefinisikan dalam ENTRYPOINT (skrip init saya) berjalan, itu muncul di log tetapi wadah saya tampaknya keluar. Jadi, alih-alih ENTRYPOINT, saya menggunakan perintah RUN untuk menjalankan skrip dan wadah masih berjalan di latar belakang.
ypahalajani

Jawaban:

49

Ini tidak benar-benar bagaimana Anda harus merancang wadah Docker Anda.

Saat merancang wadah Docker, Anda seharusnya membuatnya sedemikian rupa sehingga hanya ada satu proses yang berjalan (yaitu Anda harus memiliki satu wadah untuk Nginx, dan satu untuk pengawas atau aplikasi yang dijalankannya); selain itu, proses itu harus berjalan di latar depan.

Wadah akan "keluar" ketika proses itu sendiri keluar (dalam kasus Anda, proses itu adalah skrip bash Anda).


Namun, jika Anda benar - benar perlu (atau ingin) menjalankan beberapa layanan dalam wadah Docker Anda, pertimbangkan mulai dari "Docker Base Image" , yang digunakan runitsebagai proses pseudo-init ( runitakan tetap online saat Nginx dan Supervisor berjalan), yang akan tetap ada di latar depan sementara proses Anda yang lain melakukan hal mereka.

Mereka memiliki dokumen penting, jadi Anda harus dapat mencapai apa yang Anda coba lakukan dengan mudah.

Thomas Orozco
sumber
1
Bisakah Anda jelaskan mengapa saya hanya menjalankan satu layanan? Saya bisa menambahkan nginx ke supervisor jika perlu, tetapi tidak yakin mengapa ini perlu.
Eli
3
@ Eli Jawaban singkatnya adalah begini cara Docker bekerja. Docker hanya akan menjalankan satu proses (dan anak-anaknya) per kontainer. Dianjurkan agar proses ini menjadi proses aplikasi yang sebenarnya (sehingga jika keluar, Docker tahu), tetapi Anda memang bisa menggunakan pengawas sebagai proses itu. Perhatikan bahwa Anda harus mengonfigurasi supervisor untuk dijalankan di latar depan (yaitu tidak daemonize), yang dilakukan melalui --nodaemonopsi.
Thomas Orozco
1
@Eli Posting blog Docker ini menunjukkan bahwa menjalankan beberapa proses (dan, secara umum, melihat sebuah wadah sebagai "VPS kecil") adalah kurang optimal. Dalam kasus Anda, utas komentar mungkin akan lebih relevan daripada posting blog yang sebenarnya.
Thomas Orozco
1
Gambar dasar Docker adalah solusi buruk untuk banyak masalah perusahaan karena beberapa perusahaan serius menggunakan ubuntu, lebih memilih pohon RHEL / Centos.
Insinyur Perangkat Lunak
9
"Sedikit perusahaan yang serius" tampaknya tidak dapat dipertahankan. Pilihan OS tampaknya sepenuhnya didasarkan pada use case. Perusahaan mana pun memiliki banyak lingkungan yang berbeda termasuk penggunaan pengembang internal, penggunaan karyawan internal, dukungan penjualan, pementasan, POC, dan akhirnya produksi (dan bahkan itu adalah istilah yang tidak jelas). Saya tidak percaya OP menyebutkan kasus penggunaannya demikian, (maaf karena menjadi rewel) tetapi komentar semacam ini tampaknya merupakan jenis yang menyebarkan informasi yang sangat beralasan tanpa alasan mengapa.
John Carrell
154

Jika Anda menggunakan Dockerfile, coba:

ENTRYPOINT ["tail", "-f", "/dev/null"]

(Jelas ini hanya untuk keperluan dev, Anda tidak perlu membuat wadah tetap hidup kecuali itu menjalankan proses misalnya. Nginx ...)

Peluru Lunak
sumber
5
Saya menggunakan CMD["sleep", "1d"]tetapi solusi Anda tampaknya lebih baik
George Pligoropoulos
@GeorgiosPligoropoulos ini akan macet di baris itu; mungkin berjalan di latar belakang akan berhasil
Prashanth Sams
5
Bisa juga digunakan CMD["sleep", "infinity"].
Romain
5
atau 'kucing' tetapi orang mungkin mengatakan itu adalah pelecehan terhadap binatang. xD
lawphotog
Anda dapat menyelesaikan skrip entri Anda dengan exec tail -f /dev/nulltetapi menggunakan tailsebagai entri adalah jawaban yang salah.
Torsten Bronger
86

Saya baru saja mengalami masalah yang sama dan saya menemukan bahwa jika Anda menjalankan wadah Anda dengan bendera -tdan -d, itu terus berjalan.

docker run -td <image>

Inilah yang dilakukan oleh bendera (menurut docker run --help):

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

Yang paling penting adalah -tbendera. -dhanya memungkinkan Anda menjalankan wadah di latar belakang.

arne.z
sumber
3
Saya tidak bisa mereproduksi ini. Bisakah Anda memberikan contoh? Apakah ada sesuatu yang spesifik (misalnya: CMD) tentang Dockerfile yang kita perlukan agar ini berfungsi?
Matheus Santana
2
Ini tidak berhasil untuk saya. Saya menggunakan perintah docker logs <image>untuk memastikan itu adalah kesalahan yang menyebabkan buruh pelabuhan saya keluar. Status keluar adalah 0dan keluaran terakhir adalah konfirmasi bahwa lighttpdserver saya sedang berjalan:[ ok ] Starting web server: lighttpd.
ob1
Saya belum pernah bekerja dengan Docker untuk sementara waktu sekarang. Jadi mungkin saja antarmuka baris perintah berubah dan bahwa perintah ini tidak berfungsi lagi.
arne.z
4
Saya dapat mengkonfirmasi bahwa ini memang berfungsi dengan versi buruh pelabuhan terbaru. Jika Anda ingin melampirkan sesi ini nanti, menggunakan -dit juga akan berfungsi.
John Hamilton
1
@Long script tidak akan menerima tty, menambah exec bashatau exec shjika bash tidak diinstal, sampai akhir start.sh Kemudian Anda dapat menggunakan flag -t
123
43

Alasan keluarnya adalah karena skrip shell dijalankan pertama kali sebagai PID 1 dan saat itu selesai, PID 1 hilang, dan buruh pelabuhan hanya berjalan sementara PID 1 sedang.

Anda dapat menggunakan penyelia untuk melakukan segalanya, jika dijalankan dengan bendera "-n" diperintahkan untuk tidak melakukan daemonisasi, jadi itu akan tetap sebagai proses pertama:

CMD ["/usr/bin/supervisord", "-n"]

Dan supervisord.conf Anda:

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

Kemudian Anda dapat memiliki sebanyak mungkin proses lain yang Anda inginkan dan penyelia akan menangani proses restart jika diperlukan.

Dengan begitu Anda bisa menggunakan supervisord dalam kasus-kasus di mana Anda mungkin perlu nginx dan php5-fpm dan tidak masuk akal untuk memisahkannya.

phazei
sumber
Di mana dalam dokumen itu tertulis jika PID 1 berakhir wadah buruh pelabuhan berhenti berjalan?
8oh8
@ 8oh8 Pada dasarnya cara proses ruang nama bekerja; itu tidak spesifik Docker sebanyak "hal yang mendasari semua kontainer". Dari man7.org/linux/man-pages/man7/pid_namespaces.7.html :If the "init" process of a PID namespace terminates, the kernel terminates all of the processes in the namespace via a SIGKILL signal. This behavior reflects the fact that the "init" process is essential for the correct operation of a PID namespace.
dannysauer
40

Anda dapat menjalankan catperintah tanpa argumen seperti yang disebutkan oleh bro @ Sa'ad untuk menjaga agar wadah tetap berfungsi [sebenarnya tidak melakukan apa-apa selain menunggu input pengguna] (plugin Docker Jenkins melakukan hal yang sama)

Serge Velikanov
sumber
sebagai tambahan atas jawaban saya: tetapi pahami bahwa komposisi buruh pelabuhan (tidak di daemonisasi) digunakan untuk menunjukkan kepada Anda alur kerja wadah Anda, jadi mungkin berguna untuk mengekor file log dari layanan awal Anda. Cheers
Serge Velikanov
1
atau cat. Plugin docker jenkin melakukannya.
Sa'ad
12

Pastikan Anda menambahkan daemon off;nginx.conf kepada Anda atau menjalankannya CMD ["nginx", "-g", "daemon off;"]sesuai dengan gambar nginx resmi

Kemudian gunakan berikut ini untuk menjalankan kedua pengawas sebagai layanan dan nginx sebagai proses latar depan yang akan mencegah wadah keluar

service supervisor start && nginx

Dalam beberapa kasus, Anda perlu memiliki lebih dari satu proses dalam wadah Anda, jadi memaksa wadah untuk memiliki satu proses yang tepat tidak akan bekerja dan dapat menciptakan lebih banyak masalah dalam penyebaran.

Jadi, Anda perlu memahami pertukaran dan membuat keputusan yang sesuai.

ITech
sumber
7

Motivasi:

Tidak ada yang salah dalam menjalankan banyak proses di dalam wadah buruh pelabuhan . Jika seseorang suka menggunakan buruh pelabuhan sebagai VM ringan - baiklah. Yang lain suka membagi aplikasi mereka menjadi layanan mikro. Saya berpikir: Tumpukan LAMP dalam satu wadah? Bagus sekali.

Jawabannya:

Tetap dengan gambar dasar yang bagus seperti gambar dasar phusion . Mungkin ada yang lain. Tolong beri komentar anda.

Dan ini hanyalah sekadar permohonan untuk atasan. Karena gambar dasar phusion menyediakan pengawas selain beberapa hal lain seperti cron dan pengaturan lokal. Hal-hal yang ingin Anda siapkan saat menjalankan VM yang ringan. Untuk apa itu layak juga menyediakan koneksi ssh ke dalam wadah.

Gambar phusion itu sendiri hanya akan mulai dan terus berjalan jika Anda mengeluarkan pernyataan run docker dasar ini:

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

Atau mati sederhana:

Jika gambar dasar bukan untuk Anda ... Untuk CMD cepat agar tetap berjalan saya kira sesuatu seperti ini untuk bash:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

Atau ini untuk busybox:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

Ini bagus, karena akan segera keluar pada a docker stop. Biasa sleepatau catakan memakan waktu beberapa detik sebelum wadah keluar.

nyawa
sumber
Saya mengkustomisasi gambar dasar centos7 untuk memuat PostgreSQL 11. Anda memulainya dengan panggilan ke / usr / pgsql-11 / bin / pg_ctl tetapi pg_ctl keluar setelah server berjalan. Saran Anda untuk menggunakan perangkap bekerja sangat baik; ini adalah baris terakhir dari skrip saya pgstartwait.sh
Alchemistmatt
6

Tangkap PID dari proses ngnix dalam sebuah variabel (misalnya $ NGNIX_PID) dan pada akhir file entry point lakukan

wait $NGNIX_PID 

Dengan cara itu, wadah Anda harus berjalan sampai ngnix hidup, ketika ngnix berhenti, wadah juga berhenti

pengguna2825611
sumber