Susunan docker Cara menunggu sampai wadah siap

Pendahuluan


Ada banyak artikel tentang menjalankan wadah dan menulis docker-compose.yml . Tetapi bagi saya untuk waktu yang lama, pertanyaannya tidak jelas bagaimana melanjutkan dengan benar jika beberapa wadah tidak boleh diluncurkan sampai wadah lain siap untuk memproses permintaannya atau melakukan sejumlah pekerjaan.

Pertanyaan ini menjadi relevan setelah kami mulai aktif menggunakan docker-compose , alih-alih meluncurkan masing-masing docker.

Untuk apa ini?


Memang, biarkan aplikasi dalam wadah B tergantung pada ketersediaan layanan dalam wadah A. Dan pada saat startup, aplikasi dalam wadah B tidak menerima layanan ini. Apa yang harus dilakukan?

Ada dua opsi:

  • yang pertama adalah mati (lebih disukai dengan kode kesalahan)
  • yang kedua adalah menunggu, dan kemudian mati pula, jika aplikasi dalam wadah B tidak merespons untuk batas waktu yang diberikan

Setelah kontainer B mati, komposisi buruh pelabuhan (tergantung pada konfigurasi tentu saja) akan memulai kembali dan aplikasi dalam wadah B akan mencoba lagi untuk mencapai layanan dalam wadah A.

Ini akan berlanjut sampai layanan dalam wadah A siap untuk menanggapi permintaan, atau sampai kami melihat bahwa kontainer terus kelebihan muatan.
Dan sebenarnya, ini adalah cara normal untuk arsitektur multi-container.

Namun, khususnya, kami dihadapkan pada situasi di mana wadah A memulai dan menyiapkan data untuk wadah B. Aplikasi dalam wadah B tidak dapat memeriksa apakah data siap atau tidak, ia segera mulai bekerja dengan mereka. Karena itu, kita harus menerima dan memproses sinyal tentang kesiapan data sendiri.

Saya pikir Anda masih bisa memberikan beberapa use case. Tetapi yang paling penting, Anda perlu memahami persis mengapa Anda melakukan ini. Kalau tidak, lebih baik menggunakan alat pembuat docker standar.

Sedikit ideologi


Jika Anda membaca dokumentasi dengan cermat, maka semuanya tertulis di sana. Yaitu masing-masing
unit independen dan harus menjaga semua layanan dengan
dengan mana ia akan bekerja, tersedia baginya.

Oleh karena itu, pertanyaannya bukan untuk memulai atau tidak memulai wadah, tetapi untuk memulai
di dalam wadah, periksa kesiapan semua layanan yang diperlukan dan hanya
kemudian transfer kontrol ke aplikasi kontainer.

Bagaimana penerapannya


Untuk mengatasi masalah ini, deskripsi buruh pelabuhan-menulis banyak membantu saya, ini bagian dari itu
dan sebuah artikel tentang penggunaan entrypoint dan cmd yang tepat .

Jadi apa yang kita butuhkan:

  • ada lampiran A yang kami bungkus dalam wadah A
  • itu dimulai dan mulai merespons OK pada port 8000
  • dan juga, ada aplikasi B, yang kita mulai dari wadah B, tetapi itu harus mulai bekerja tidak lebih awal dari aplikasi A akan mulai menanggapi permintaan pada port 8000

Dokumentasi resmi menawarkan dua cara untuk mengatasi masalah ini.

Yang pertama adalah menulis titik masuk Anda sendiri dalam wadah, yang akan melakukan semua pemeriksaan, dan kemudian memulai aplikasi yang berfungsi.

Yang kedua adalah menggunakan file batch yang sudah ditulis wait-for-it.sh .
Kami mencoba keduanya.

Menulis Entrypoint Anda Sendiri


Apa itu entrypoint ?

Ini hanya file yang dapat dieksekusi yang Anda tentukan saat membuat wadah di Dockerfile di bidang ENTRYPOINT . File ini, sebagaimana telah disebutkan, melakukan pemeriksaan, dan kemudian meluncurkan aplikasi utama wadah.

Jadi apa yang kita dapatkan:

Buat folder Entrypoint .

Ini memiliki dua subfolder - container_A dan container_B . Kami akan membuat wadah kami di dalamnya.

Untuk penampung A, mari kita ambil http server sederhana dengan python. Dia, setelah memulai, mulai merespons untuk mendapatkan permintaan pada port 8000.

Untuk menjadikan percobaan kami lebih eksplisit, kami menetapkan penundaan 15 detik sebelum memulai server.

Ternyata file buruh pelabuhan berikut untuk wadah A :

FROM python:3 EXPOSE 8000 CMD sleep 15 && python3 -m http.server --cgi 

Untuk kontainer B, buat file buruh pelabuhan berikut untuk wadah B :

 FROM ubuntu:18.04 RUN apt-get update RUN apt-get install -y curl COPY ./entrypoint.sh /usr/bin/entrypoint.sh ENTRYPOINT [ "entrypoint.sh" ] CMD ["echo", "!!!!!!!! Container_A is available now !!!!!!!!"] 

Dan menempatkan entrypoint.sh kita dapat dieksekusi di folder yang sama. Kami akan memilikinya seperti ini

 #!/bin/bash set -e host="conteiner_a" port="8000" cmd="$@" >&2 echo "!!!!!!!! Check conteiner_a for available !!!!!!!!" until curl http://"$host":"$port"; do >&2 echo "Conteiner_A is unavailable - sleeping" sleep 1 done >&2 echo "Conteiner_A is up - executing command" exec $cmd 

Apa yang terjadi dalam wadah B:

  • Saat dimulai, ia mulai ENTRYPOINT , mis. meluncurkan entrypoint.sh
  • entrypoint.sh , menggunakan curl , mulai polling port 8000 untuk container A. Ia melakukan ini hingga menerima respons 200 (mis. curl dalam hal ini akan berakhir dengan hasil nol dan loop akan berakhir)
  • Ketika 200 diterima, loop berakhir dan kontrol beralih ke perintah yang ditentukan dalam variabel $ cmd . Dan itu menunjukkan apa yang kami tunjukkan dalam file buruh pelabuhan di bidang CMD , mis. echo "!!! Container_A tersedia sekarang !!!!!!!!" Mengapa demikian, dijelaskan dalam artikel di atas
  • Kami mencetak - !!! Container_A tersedia sekarang !!! dan menyimpulkan.

Kami akan memulai semuanya dengan menulis buruh pelabuhan .

docker-compose.yml di sini kita memiliki ini:

 version: '3' networks: waiting_for_conteiner: services: conteiner_a: build: ./conteiner_A container_name: conteiner_a image: conteiner_a restart: unless-stopped networks: - waiting_for_conteiner ports: - 8000:8000 conteiner_b: build: ./conteiner_B container_name: conteiner_b image: waiting_for_conteiner.entrypoint.conteiner_b restart: "no" networks: - waiting_for_conteiner 

Di sini, di conteiner_a, tidak perlu menentukan port: 8000: 8000 . Ini dilakukan untuk dapat memverifikasi operasi server http yang berjalan di dalamnya dari luar.

Juga, wadah B tidak memulai kembali setelah dimatikan.

Kami meluncurkan:

 docker-compose up —-build 

Kami melihat bahwa selama 15 detik ada pesan tentang tidak tersedianya wadah A, dan kemudian

 conteiner_b | Conteiner_A is unavailable - sleeping conteiner_b | % Total % Received % Xferd Average Speed Time Time Time Current conteiner_b | Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> conteiner_b | <html> conteiner_b | <head> conteiner_b | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> conteiner_b | <title>Directory listing for /</title> conteiner_b | </head> conteiner_b | <body> conteiner_b | <h1>Directory listing for /</h1> conteiner_b | <hr> conteiner_b | <ul> conteiner_b | <li><a href=".dockerenv">.dockerenv</a></li> conteiner_b | <li><a href="bin/">bin/</a></li> conteiner_b | <li><a href="boot/">boot/</a></li> conteiner_b | <li><a href="dev/">dev/</a></li> conteiner_b | <li><a href="etc/">etc/</a></li> conteiner_b | <li><a href="home/">home/</a></li> conteiner_b | <li><a href="lib/">lib/</a></li> conteiner_b | <li><a href="lib64/">lib64/</a></li> conteiner_b | <li><a href="media/">media/</a></li> conteiner_b | <li><a href="mnt/">mnt/</a></li> conteiner_b | <li><a href="opt/">opt/</a></li> conteiner_b | <li><a href="proc/">proc/</a></li> conteiner_b | <li><a href="root/">root/</a></li> conteiner_b | <li><a href="run/">run/</a></li> conteiner_b | <li><a href="sbin/">sbin/</a></li> conteiner_b | <li><a href="srv/">srv/</a></li> conteiner_b | <li><a href="sys/">sys/</a></li> conteiner_b | <li><a href="tmp/">tmp/</a></li> conteiner_b | <li><a href="usr/">usr/</a></li> conteiner_b | <li><a href="var/">var/</a></li> conteiner_b | </ul> conteiner_b | <hr> conteiner_b | </body> conteiner_b | </html> 100 987 100 987 0 0 98700 0 --:--:-- --:--:-- --:--:-- 107k conteiner_b | Conteiner_A is up - executing command conteiner_b | !!!!!!!! Container_A is available now !!!!!!!! 

Kami mendapatkan jawaban atas permintaan Anda, cetak !!! Container_A tersedia sekarang !!!!!!!! dan menyimpulkan.

Menggunakan wait-for-it.sh


Perlu segera mengatakan bahwa jalur ini tidak berfungsi untuk kami seperti yang dijelaskan dalam dokumentasi.
Yaitu, diketahui bahwa jika ENTRYPOINT dan CMD ditulis dalam Dockerfile , maka ketika wadah dimulai, perintah dari ENTRYPOINT akan dieksekusi, dan konten CMD akan diteruskan ke parameter tersebut.

Diketahui juga bahwa ENTRYPOINT dan CMD yang ditentukan dalam Dockerfile dapat didefinisikan ulang di docker-compose.yml

Format startup wait-for-it.sh adalah sebagai berikut:

 wait-for-it.sh __ -- ___ 

Kemudian, seperti yang ditunjukkan dalam artikel , kita dapat mendefinisikan ENTRYPOINT baru di docker-compose.yml , dan CMD akan diganti dari Dockerfile .

Jadi, kita dapat:

File Docker untuk kontainer A tetap tidak berubah:

 FROM python:3 EXPOSE 8000 CMD sleep 15 && python3 -m http.server --cgi 

File docker untuk kontainer B

 FROM ubuntu:18.04 COPY ./wait-for-it.sh /usr/bin/wait-for-it.sh CMD ["echo", "!!!!!!!! Container_A is available now !!!!!!!!"] 

Docker-compose.yml terlihat seperti ini:

 version: '3' networks: waiting_for_conteiner: services: conteiner_a: build: ./conteiner_A container_name: conteiner_a image: conteiner_a restart: unless-stopped networks: - waiting_for_conteiner ports: - 8000:8000 conteiner_b: build: ./conteiner_B container_name: conteiner_b image: waiting_for_conteiner.wait_for_it.conteiner_b restart: "no" networks: - waiting_for_conteiner entrypoint: ["wait-for-it.sh", "-s" , "-t", "20", "conteiner_a:8000", "--"] 

Kami menjalankan perintah wait-for-it , suruh menunggu 20 detik hingga container A hidup kembali, dan tentukan parameter lain “-” , yang akan memisahkan parameter wait-for-it dari program yang akan diluncurkan setelah selesai.

Kami mencoba!
Dan sayangnya, kami tidak mendapatkan apa-apa.

Jika kita memeriksa dengan argumen apa kita menjalankan wait-for-it, maka kita akan melihat bahwa hanya apa yang kita tentukan di entry point yang dilewatkan ke sana , CMD dari wadah tidak terpasang.

Opsi kerja


Lalu, hanya ada satu opsi. Apa yang kami tentukan dalam CMD di Dockerfile , kami harus mentransfer ke perintah di docker-compose.yml .

Kemudian, biarkan Dockerfile dari wadah B tidak berubah, dan docker-compose.yml akan terlihat seperti ini:

 version: '3' networks: waiting_for_conteiner: services: conteiner_a: build: ./conteiner_A container_name: conteiner_a image: conteiner_a restart: unless-stopped networks: - waiting_for_conteiner ports: - 8000:8000 conteiner_b: build: ./conteiner_B container_name: conteiner_b image: waiting_for_conteiner.wait_for_it.conteiner_b restart: "no" networks: - waiting_for_conteiner entrypoint: ["wait-for-it.sh", "-s" ,"-t", "20", "conteiner_a:8000", "--"] command: ["echo", "!!!!!!!! Container_A is available now !!!!!!!!"] 

Dan dalam versi ini, ini berfungsi.

Kesimpulannya, harus dikatakan bahwa menurut pendapat kami, cara yang benar adalah yang pertama. Ini adalah yang paling universal dan memungkinkan Anda untuk melakukan pemeriksaan kesiapan dengan cara apa pun yang memungkinkan. Tunggu-itu- hanya utilitas bermanfaat yang dapat Anda gunakan baik secara terpisah atau dengan menanamkan di entrypoint Anda.

Source: https://habr.com/ru/post/id454552/


All Articles