Saya mencoba memastikan bahwa penampung aplikasi saya tidak menjalankan migrasi / mulai sampai penampung db dimulai dan SIAP menerima koneksi.
Jadi saya memutuskan untuk menggunakan healthcheck dan bergantung pada opsi di file docker compose v2.
Di aplikasi, saya memiliki yang berikut ini
app:
...
depends_on:
db:
condition: service_healthy
Sebaliknya, db memiliki pemeriksaan kesehatan berikut
db:
...
healthcheck:
test: TEST_GOES_HERE
timeout: 20s
retries: 10
Saya telah mencoba beberapa pendekatan seperti:
- memastikan db DIR dibuat
test: ["CMD", "test -f var/lib/mysql/db"]
- Mendapatkan versi mysql:
test: ["CMD", "echo 'SELECT version();'| mysql"]
- Ping admin (tandai penampung db sebagai sehat tetapi tampaknya bukan tes yang valid)
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
Apakah ada yang punya solusi untuk ini?
mysql
docker
docker-compose
dockerfile
John Kariuki
sumber
sumber
mysql -u USER -p PASSWORD -h MYSQLSERVERNAME -e 'select * from foo...' database-name
Jawaban:
Wadah api tidak akan mulai sampai wadah db sehat (pada dasarnya sampai mysqladmin aktif dan menerima koneksi.)
sumber
mysqladmin ping
akan mengembalikan positif palsu jika server berjalan tetapi belum menerima koneksi.condition
underdepends_on
tidak didukung di versi 3+test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD' ]
- jika Anda ditentukanMYSQL_ROOT_PASSWORD
dienvironments
bagian.Jika Anda menggunakan docker-compose v3 + ,
condition
sebagai opsidepends_on
telah dihapus .Jalur yang dianjurkan adalah dengan menggunakan lebih
wait-for-it
,dockerize
atauwait-for
. Didocker-compose.yml
file Anda , ubah perintah Anda menjadi:command: sh -c 'bin/wait-for db:3306 -- bundle exec rails s'
Saya pribadi lebih suka
wait-for
karena dapat berjalan dalam wadah Alpine (sh
kompatibel, tidak bergantung padabash
). Kekurangannya adalah tergantung padanetcat
, jadi jika Anda memutuskan untuk menggunakannya, pastikan Anda telahnetcat
menginstalnya di container, atau menginstalnya di Dockerfile Anda, misalnya dengan:RUN apt-get -q update && apt-get -qy install netcat
Saya juga membuat fork
wait-for
proyek sehingga dapat memeriksa status HTTP yang sehat (yang digunakannyawget
). Kemudian Anda dapat melakukan sesuatu seperti itu:command: sh -c 'bin/wait-for http://api/ping -- jest test'
PS: Seorang PR juga siap digabung untuk menambah kapasitas itu ke
wait-for
proyek.sumber
Ini sudah cukup
version: '2.1' services: mysql: image: mysql ports: ['3306:3306'] environment: MYSQL_USER: myuser MYSQL_PASSWORD: mypassword healthcheck: test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
sumber
$
?$
Im mengakses variabel env dari host maka saya kira? bagus sekali terima kasih!Jika Anda dapat mengubah wadah untuk menunggu mysql siap, lakukanlah.
Jika Anda tidak memiliki kontrol wadah tempat Anda ingin menyambungkan database, Anda bisa mencoba menunggu port tertentu.
Untuk tujuan itu, saya menggunakan skrip kecil untuk menunggu port tertentu diekspos oleh penampung lain.
Dalam contoh ini, myserver akan menunggu port 3306 dari container mydb dapat dijangkau.
# Your database mydb: image: mysql ports: - "3306:3306" volumes: - yourDataDir:/var/lib/mysql # Your server myserver: image: myserver ports: - "....:...." entrypoint: ./wait-for-it.sh mydb:3306 -- ./yourEntryPoint.sh
Anda dapat menemukan dokumentasi skrip wait-for-it di sini
sumber
wait-for-it.sh
sebelumnya tetapi itu menimpa Dockerfile default, bukan? Bagaimana tampilan entrypoint.sh?Hai untuk healthcheck sederhana menggunakan docker-compose v2.1 , saya menggunakan:
Pada dasarnya ini menjalankan
mysql
perintah sederhanaSHOW DATABASES;
menggunakan sebagai contoh penggunaroot
dengan kata sandirootpasswd
di database.Jika perintah berhasil maka db sudah up dan ready jadi jalur healthcheck. Anda dapat menggunakannya
interval
untuk menguji pada interval.Menghapus bidang lain untuk visibilitas, berikut ini akan terlihat seperti di Anda
docker-compose.yaml
.version: '2.1' services: db: ... # Other db configuration (image, port, volumes, ...) healthcheck: test: "/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\"" interval: 2s timeout: 20s retries: 10 app: ... # Other app configuration depends_on: db: condition: service_healthy
sumber
command: ["/home/app/jswebservice/wait-for-it.sh", "maria:3306", "--", "node", "webservice.js"]
--execute \"SHOW DATABASES;\"
itulah yang membuatnya menunggu saya hingga database tersedia untuk diakses aplikasiSaya memodifikasi
docker-compose.yml
sesuai contoh berikut dan berhasil.mysql: image: mysql:5.6 ports: - "3306:3306" volumes: # Preload files for data - ../schemaAndSeedData:/docker-entrypoint-initdb.d environment: MYSQL_ROOT_PASSWORD: rootPass MYSQL_DATABASE: DefaultDB MYSQL_USER: usr MYSQL_PASSWORD: usr healthcheck: test: mysql --user=root --password=rootPass -e 'Design your own check script ' LastSchema
Dalam kasus saya
../schemaAndSeedData
berisi beberapa skema dan file sql penyemaian data.Design your own check script
bisa mirip dengan berikutselect * from LastSchema.LastDBInsert
.Sementara kode wadah bergantung web adalah
depends_on: mysql: condition: service_healthy
sumber
LastSchema.LastDBInsert
default MySQL atau mesin database tertentu?Saya memiliki masalah yang sama, saya membuat skrip bash eksternal untuk tujuan ini (Ini terinspirasi oleh jawaban Maxim). Ganti
mysql-container-name
dengan nama wadah MySQL Anda dan juga kata sandi / pengguna diperlukan:bin / wait-for-mysql.sh :
#!/bin/sh until docker container exec -it mysql-container-name mysqladmin ping -P 3306 -proot | grep "mysqld is alive" ; do >&2 echo "MySQL is unavailable - waiting for it... 😴" sleep 1 done
Di MakeFile saya, saya memanggil skrip ini tepat setelah
docker-compose
panggilan saya :wait-for-mysql: ## Wait for MySQL to be ready bin/wait-for-mysql.sh run: up wait-for-mysql reload serve ## Start everything...
Kemudian saya dapat memanggil perintah lain tanpa kesalahan:
Contoh keluaran:
docker-compose -f docker-compose.yaml up -d Creating network "strangebuzzcom_default" with the default driver Creating sb-elasticsearch ... done Creating sb-redis ... done Creating sb-db ... done Creating sb-app ... done Creating sb-kibana ... done Creating sb-elasticsearch-head ... done Creating sb-adminer ... done bin/wait-for-mysql.sh MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 MySQL is unavailable - waiting for it... 😴 mysqld is alive php bin/console doctrine:cache:clear-metadata // Clearing all Metadata cache entries [OK] Successfully deleted cache entries.
Saya telah menghapus health check karena sekarang tidak berguna dengan pendekatan ini.
sumber
Menambahkan solusi yang diperbarui untuk pendekatan healthcheck. Cuplikan sederhana:
healthcheck: test: out=$$(mysqladmin ping -h localhost -P 3306 -u foo --password=bar 2>&1); echo $$out | grep 'mysqld is alive' || { echo $$out; exit 1; }
Penjelasan : Karena
mysqladmin ping
mengembalikan positif palsu (terutama untuk kata sandi yang salah), saya menyimpan output ke variabel sementara, kemudian menggunakangrep
untuk menemukan output yang diharapkan (mysqld is alive
). Jika ditemukan maka akan mengembalikan kode kesalahan 0. Jika tidak ditemukan, saya mencetak seluruh pesan, dan mengembalikan 1 kode kesalahan.Cuplikan diperpanjang:
version: "3.8" services: db: image: linuxserver/mariadb environment: - FILE__MYSQL_ROOT_PASSWORD=/run/secrets/mysql_root_password - FILE__MYSQL_PASSWORD=/run/secrets/mysql_password secrets: - mysql_root_password - mysql_password healthcheck: test: out=$$(mysqladmin ping -h localhost -P 3306 -u root --password=$$(cat $${FILE__MYSQL_ROOT_PASSWORD}) 2>&1); echo $$out | grep 'mysqld is alive' || { echo $$out; exit 1; } secrets: mysql_root_password: file: ${SECRETSDIR}/mysql_root_password mysql_password: file: ${SECRETSDIR}/mysql_password
Penjelasan : Saya menggunakan rahasia buruh pelabuhan daripada variabel env (tapi ini bisa dicapai dengan vars env biasa juga). Penggunaan
$$
is untuk$
tanda literal yang dilucuti saat diteruskan ke container.Output dari
docker inspect --format "{{json .State.Health }}" db | jq
berbagai kesempatan:Semuanya baik-baik saja:
{ "Status": "healthy", "FailingStreak": 0, "Log": [ { { "Start": "2020-07-20T01:03:02.326287492+03:00", "End": "2020-07-20T01:03:02.915911035+03:00", "ExitCode": 0, "Output": "mysqld is alive\n" } ] }
DB belum menyala (belum):
{ "Status": "starting", "FailingStreak": 1, "Log": [ { "Start": "2020-07-20T01:02:58.816483336+03:00", "End": "2020-07-20T01:02:59.401765146+03:00", "ExitCode": 1, "Output": "\u0007mysqladmin: connect to server at 'localhost' failed error: 'Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 \"No such file or directory\")' Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists!\n" } ] }
Kata sandi salah:
{ "Status": "unhealthy", "FailingStreak": 13, "Log": [ { "Start": "2020-07-20T00:56:34.303714097+03:00", "End": "2020-07-20T00:56:34.845972979+03:00", "ExitCode": 1, "Output": "\u0007mysqladmin: connect to server at 'localhost' failed error: 'Access denied for user 'root'@'localhost' (using password: YES)'\n" } ] }
sumber
RESTART ON-FAILURE
Sejak v3
condition: service_healthy
tidak lagi tersedia. Idenya adalah bahwa pengembang harus menerapkan mekanisme pemulihan kerusakan dalam aplikasi itu sendiri. Namun untuk kasus penggunaan sederhana, cara sederhana untuk mengatasi masalah ini adalah menggunakanrestart
opsi.Jika status layanan mysql menyebabkan aplikasi
exited with code 1
Anda, Anda dapat menggunakan salah saturestart
opsi kebijakan yang tersedia. misalnya,on-failure
sumber