डोजर-कंपोज़ चेक करें कि क्या mysql कनेक्शन तैयार है


96

मैं यह सुनिश्चित करने की कोशिश कर रहा हूं कि मेरा ऐप कंटेनर माइग्रेशन / स्टार्ट न चलाए जब तक कि डीबी कंटेनर शुरू न हो जाए और कनेक्शन स्वीकार करने के लिए तैयार रहें।

इसलिए मैंने हेल्दीचेक का उपयोग करने का निर्णय लिया और डॉक्यू कम्पोज फाइल v2 में विकल्प पर निर्भर करता है।

एप्लिकेशन में, मेरे पास निम्नलिखित हैं

app:
    ...
    depends_on:
      db:
      condition: service_healthy

दूसरी ओर db में निम्न स्वास्थ्य जांच है

db:
  ...
  healthcheck:
    test: TEST_GOES_HERE
    timeout: 20s
    retries: 10

मैंने कुछ तरीकों की कोशिश की है जैसे:

  1. सुनिश्चित करें कि db DIR बनाया गया है test: ["CMD", "test -f var/lib/mysql/db"]
  2. Mysql संस्करण प्राप्त करना: test: ["CMD", "echo 'SELECT version();'| mysql"]
  3. व्यवस्थापक को पिंग करें (db कंटेनर को स्वस्थ के रूप में चिह्नित करता है लेकिन एक वैध परीक्षण नहीं लगता है) test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]

क्या किसी के पास इसका कोई समाधान है?


आपने एक DB के लिए एक डॉकटर बनाया? कृपया मुझे बताएं कि आपका डेटा आपके अनुप्रयोग स्वास्थ्य के लिए इस कंटेनर के बाहर है
जॉर्ज कैम्पोस

या कम से कम यह एक परीक्षण रोकनेवाला है।
जॉर्ज कैम्पोस

यह वास्तव में केवल विकास / परीक्षण के लिए है।
जॉन करुकी

2
मुझे लगता है कि आपको mysql में एक क्वेरी को जोड़ने और चलाने के लिए एक कमांड का उपयोग करना चाहिए, आपके द्वारा दिए गए नमूनों में से कोई भी ऐसा नहीं है: कुछ इस तरह से:mysql -u USER -p PASSWORD -h MYSQLSERVERNAME -e 'select * from foo...' database-name
जॉर्ज कैम्पस

1
@JorgeCampos ठीक है धन्यवाद। आमतौर पर मेरे पास एक डीबी कंटेनर होता है, लेकिन डेटा के लिए मैप वॉल्यूम। ताकि अगर कंटेनर नीचे चला गया तो यह डेटा अगले पल के लिए बना रहेगा।
एस ..

जवाबों:


86
version: "2.1"
services:
    api:
        build: .
        container_name: api
        ports:
            - "8080:8080"
        depends_on:
            db:
                condition: service_healthy
    db:
        container_name: db
        image: mysql
        ports:
            - "3306"
        environment:
            MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
            MYSQL_USER: "user"
            MYSQL_PASSWORD: "password"
            MYSQL_DATABASE: "database"
        healthcheck:
            test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
            timeout: 20s
            retries: 10

एपी कंटेनर तब तक शुरू नहीं होगा जब तक कि डीबी कंटेनर स्वस्थ न हो जाए (मूल रूप से जब तक माईसक्लाडमिन ऊपर है और कनेक्शन स्वीकार कर रहा है।)


12
mysqladmin pingयदि सर्वर चल रहा है लेकिन अभी तक कनेक्शन स्वीकार नहीं कर रहा है तो एक गलत पॉज़िटिव लौटाएगा।
halfpastfour.am

55
2017 के लोगों के लिए बस FYI करें: conditionअंडर depends_on3 संस्करण में समर्थित नहीं है
मिंट

@ याकूबक्रिथोफ़ मैं एक ही मुद्दे का सामना कर रहा हूं ... क्या कोई काम है, कुछ ऐसा है जैसे नींद या बाहर निकलने की स्थिति के लिए पुन: प्रयास करें
मुकेश अग्रवाल

1
@dKen ने नीचे दिए गए मेरे जवाब को देखें stackoverflow.com/a/45058879/279272 , मुझे आशा है कि यह आपके लिए भी काम करेगा।
मुकेश अग्रवाल

1
पासवर्ड का उपयोग करके यह जांचने के लिए: test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD' ]- यदि आपने अनुभाग MYSQL_ROOT_PASSWORDमें परिभाषित किया है environments
जुमे

23

यदि आप do-compose v3 + का उपयोग कर रहे हैं , तो हटाए गएcondition विकल्प के depends_onरूप में ।

सिफारिश पथ का उपयोग करने के बजाय है wait-for-it, dockerizeया wait-for। अपनी docker-compose.ymlफ़ाइल में, अपनी कमांड को बदलें:

command: sh -c 'bin/wait-for db:3306 -- bundle exec rails s'

मैं व्यक्तिगत रूप से पसंद करता हूं wait-forक्योंकि यह अल्पाइन कंटेनर में चल सकता है ( shसंगत, कोई निर्भरता नहीं bash)। दोष यह है कि यह निर्भर करता है netcat, इसलिए यदि आप इसका उपयोग करने का निर्णय लेते हैं, तो सुनिश्चित करें कि आपने netcatकंटेनर में स्थापित किया है, या इसे अपने डॉकफाइल में स्थापित करें, उदाहरण के लिए:

RUN apt-get -q update && apt-get -qy install netcat

मैंने परियोजना को भी कांटा थाwait-for ताकि यह स्वस्थ HTTP स्थिति (यह उपयोग करता है wget) की जांच कर सके। तब आप ऐसा कुछ कर सकते हैं:

command: sh -c 'bin/wait-for http://api/ping -- jest test'

पुनश्च: एक पीआर भीwait-for परियोजना में उस क्षमता को जोड़ने के लिए विलय करने के लिए तैयार है ।


15

यह पर्याप्त होना चाहिए

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

2
किसके लिए दोगुना $है?
InsOp

5
@InsOp विशेष सिंटेक्स आप env चर $ के साथ शुरू होता है से बचने के लिए स्वास्थ्य जांच परीक्षण आदेश में उपयोग करने के लिए, यानी $$ MYSQL_PASSWORD $ MYSQL_PASSWORD है, जो खुद इस ठोस उदाहरण में mypassword में परिणाम देगा में परिणाम होगा है
Maksim Kostromin

तो इस im के साथ कंटेनर के अंदर env वैरिएबल एक्सेस कर रहा है? एक ही $Im मेजबान से env चर तक पहुँचने के साथ तो मुझे लगता है? बहुत अच्छा धन्यवाद!
InsOp

10

यदि आप कन्टेनर को बदल सकते हैं तो mysql के इंतजार के लिए तैयार रहें।

यदि आपके पास उस कंटेनर का नियंत्रण नहीं है जिसे आप डेटाबेस से कनेक्ट करना चाहते हैं, तो आप विशिष्ट पोर्ट के लिए प्रतीक्षा करने का प्रयास कर सकते हैं।

उस प्रयोजन के लिए, मैं किसी अन्य कंटेनर द्वारा उजागर किए गए विशिष्ट पोर्ट की प्रतीक्षा करने के लिए एक छोटी स्क्रिप्ट का उपयोग कर रहा हूं।

इस उदाहरण में, myserver mydb कंटेनर के पोर्ट 3306 के पुनःप्राप्त होने की प्रतीक्षा करेगा ।

# 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

आप स्क्रिप्ट प्रतीक्षा के लिए यह दस्तावेज़ीकरण देख सकते हैं यहां


मैंने wait-for-it.sh पहले प्रयोग करने की कोशिश की थी लेकिन यह डिफ़ॉल्ट डॉकफाइल को सही से ओवरराइड करता है? कैसा लगता है एंट्रीपॉइंट.श?
जॉन करियुकी

प्रवेश बिंदु आपकी छवि पर निर्भर करता है। आप इसे डॉकटर निरीक्षण <छवि आईडी> के साथ देख सकते हैं। यह सेवा उपलब्ध होने की प्रतीक्षा करनी चाहिए और आपके प्रवेश बिंदु को कॉल करना चाहिए।
नोनो

ठीक है न ? क्या आप समझे?
नोनो

सही बात। हाँ।
जॉन करुकी

6
चेतावनी: MySQL 5.5 (संभवतः नए संस्करण के रूप में अच्छी तरह से) अभी भी प्रारंभिक करते समय प्रतिक्रिया कर सकते हैं।
ब्लेज़

8

डॉक-कम्पोज़ v2.1 का उपयोग करते हुए एक सरल स्वास्थ्य परीक्षण के लिए नमस्ते , मैंने उपयोग किया:

/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\"

मूल रूप से यह डेटाबेस में पासवर्ड वाले उपयोगकर्ता के रूप में उपयोग करके एक साधारण mysqlकमांड चलाता है ।SHOW DATABASES;rootrootpasswd

यदि कमांड सफल होता है तो db ऊपर और तैयार होता है इसलिए स्वास्थ्यवर्धक पथ। आप उपयोग कर सकते हैं intervalतो यह अंतराल पर परीक्षण करता है।

दृश्यता के लिए दूसरे क्षेत्र को हटाते हुए, यहां वही है जो आपके में दिखाई देगा 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

1
चेतावनी: रचना फ़ाइल के "संस्करण 3" के साथ, "स्थिति" समर्थन अब उपलब्ध नहीं है। देखें docs.docker.com/compose/compose-file/#depends_on
बार्टोज़क

1
आपको प्रतीक्षा-for-it.sh स्क्रिप्ट के साथ कमांड सुविधा का उपयोग करना चाहिए । मुझे यह इस तरह से कर रहा है:command: ["/home/app/jswebservice/wait-for-it.sh", "maria:3306", "--", "node", "webservice.js"]
बार्टोज़्ज़

@BartoszKI इसे नहीं समझता है। क्या आप कृपया विवरण के साथ पूर्ण उत्तर जोड़ सकते हैं? मैं ठीक उसी समस्या का सामना कर रहा हूं, लेकिन मैं यह काम नहीं कर सकता।
थादू एंटोनियो फरेरा मेलो

सुनिश्चित करें कि आप v2.1 का उपयोग कर रहे हैं, अन्यथा v3.0 और उसके बाद के लिए नए दिशानिर्देशों का पालन करें।
सिलहारे

1
--execute \"SHOW DATABASES;\"क्या यह मेरे लिए इंतजार कर रहा है जब तक डेटाबेस आवेदन के लिए उपलब्ध होने के लिए उपलब्ध नहीं था
tsuz

6

मैंने docker-compose.ymlनिम्नलिखित उदाहरण के अनुसार संशोधित किया और इसने काम किया।

  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

मेरे मामले ../schemaAndSeedDataमें कई स्कीमा और डेटा सीडिंग sql फाइलें हैं। Design your own check scriptनिम्नलिखित के समान हो सकता है select * from LastSchema.LastDBInsert

जबकि वेब डिपेंडेंट कंटेनर कोड था

depends_on:
  mysql:
    condition: service_healthy

यह आपके लिए काम कर सकता है लेकिन मैं अनिश्चित हूं कि यह सब MySQL इंजन में समर्थित है या नहीं।
halfpastfour.am

मैं डेटाबेस इंजन जैसे कि InnoDB, MyISAM आदि के बारे में बात कर रहा हूँ क्या LastSchema.LastDBInsertकोई MySQL डिफ़ॉल्ट या डेटाबेस इंजन विशिष्ट है?
halfpastfour.am

नहीं, यह mysql में भी डिफ़ॉल्ट नहीं है। यह सिर्फ एक नमूना था। एक डमी क्वेरी।
मुकेश अग्रवाल

6
चेतावनी: रचना फ़ाइल के "संस्करण 3" के साथ, "स्थिति" समर्थन अब उपलब्ध नहीं है। देखें docs.docker.com/compose/compose-file/#depends_on
बार्टोज़क

4

Healthcheck दृष्टिकोण के लिए एक अद्यतन समाधान जोड़ना। सरल स्निपेट:

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; }

स्पष्टीकरण : चूंकि mysqladmin pingझूठे सकारात्मक (विशेष रूप से गलत पासवर्ड के लिए) रिटर्न, मैं आउटपुट को एक अस्थायी चर में सहेज रहा हूं, फिर grepअपेक्षित आउटपुट ( mysqld is alive) खोजने के लिए उपयोग कर रहा हूं । यदि यह पाया जाता है कि यह 0 त्रुटि कोड लौटाएगा। यदि यह नहीं मिला है, तो मैं पूरे संदेश को प्रिंट कर रहा हूं, और 1 त्रुटि कोड वापस कर रहा हूं।

विस्तारित स्निपेट:

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

स्पष्टीकरण : मैं env वेरिएबल्स के बजाय docker रहस्यों का उपयोग कर रहा हूं (लेकिन इसे नियमित रूप से env var के साथ भी प्राप्त किया जा सकता है)। का उपयोग $$शाब्दिक $संकेत के लिए होता है जो कंटेनर में जाने पर छीन लिया जाता है।

docker inspect --format "{{json .State.Health }}" db | jqविभिन्न अवसरों पर आउटपुट :

सब ठीक है:

{
  "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 अप (अभी तक) नहीं है:

{
  "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"
    }
  ]
}

गलत पासवर्ड:

{
  "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"
    }
  ]
}

3

मुझे एक ही समस्या थी, मैंने इस उद्देश्य के लिए एक बाहरी बैश स्क्रिप्ट बनाई (यह मैक्सिम उत्तर से प्रेरित है)। mysql-container-nameअपने MySQL कंटेनर के नाम से बदलें और पासवर्ड / उपयोगकर्ता की भी जरूरत है:

बिन / प्रतीक्षा-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

मेरे मेकफाइल में, मैं अपने docker-composeकॉल के बाद इस स्क्रिप्ट को कॉल करता हूं :

wait-for-mysql: ## Wait for MySQL to be ready
    bin/wait-for-mysql.sh

run: up wait-for-mysql reload serve ## Start everything...

फिर मैं त्रुटि के बिना अन्य कमांड को कॉल कर सकता हूं:

ड्राइवर में एक अपवाद हुआ: SQLSTATE [HY000] [2006] MySQL सर्वर चला गया है

आउटपुट उदाहरण:

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.

मैंने स्वास्थ्य जांच को नष्ट कर दिया है क्योंकि यह इस दृष्टिकोण के साथ अब बेकार है।


2

रेस्टार्ट ऑन-फेल्योर

चूंकि v3 condition: service_healthyअब उपलब्ध नहीं है। विचार यह है कि डेवलपर को ऐप के भीतर ही क्रैश रिकवरी के लिए तंत्र लागू करना चाहिए। हालाँकि सरल उपयोग मामलों के लिए इस समस्या को हल करने का एक सरल तरीका restartविकल्प का उपयोग करना है।

यदि mysql सेवा स्थिति आपके आवेदन का कारण बनती है, exited with code 1तो आप restartउपलब्ध पॉलिसी विकल्पों में से किसी एक का उपयोग कर सकते हैं । जैसे,on-failure

version: "3"

services:

    app:
      ...
      depends_on:
        - db:
      restart: on-failure
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.