Docker-ის health check პირველ შემოწმებას კონტეინერის გაშვებიდან მთელი ერთი interval-ის შემდეგ ასრულებს და არა მაშინვე. ნაგულისხმევი მნიშვნელობებით ეს 30 წამი health: starting-ია. --interval=1h-ის შემთხვევაში ეს ერთი საათია და ყველაფერი, რაც service_healthy-ს ელოდება, იმავე საათს ელოდება. გამოსავალი კონტეინერის მთელი სიცოცხლის განმავლობაში უფრო მოკლე interval არ არის. დააყენე საკმარისად გრძელი start_period, რომ აპს ჩატვირთვა მოასწროს, და Docker Engine 25.0-ზე ან უფრო ახალზე დაამატე მოკლე start_interval. ასე შემოწმება ჩატვირთვისას სწრაფად ხდება, აპის ამოქმედების შემდეგ კი იშვიათად. კიდევ ერთი რამ, რასაც ხშირად ურევენ: unhealthy კონტეინერი განაგრძობს მუშაობას. უბრალო Docker მას არ რესტარტავს და Compose-იც არ რესტარტავს.
ეს პოსტი დროით პარამეტრებს დაწვრილებით განიხილავს: ხუთივე პარამეტრს, იმას, თუ როგორ ჯამდება ისინი "რამდენ ხანში გახდება healthy" და "რამდენ ხანში გახდება unhealthy" მნიშვნელობებად, Dockerfile-ისა და Compose-ის სინტაქსს გვერდიგვერდ, შემოწმების დაწერას იმ image-ისთვის, სადაც curl არ არის, და შედეგის წაკითხვას. რა უნდა შეამოწმოს თავად endpoint-მა და რატომ არის liveness და readiness სხვადასხვა კითხვა, იხილე graceful shutdown და რეალური health check-ები. როგორ ჯდება health check სრულ სტეკში proxy-თი და მონაცემთა ბაზით, იხილე Docker Compose პატარა სტეკებისთვის.
ხუთი დროითი პარამეტრი და მათი ნაგულისხმევი მნიშვნელობები#
Health check არის ბრძანება, რომელსაც Docker კონტეინერის შიგნით ტაიმერით უშვებს. გასვლის კოდი 0 ნიშნავს healthy-ს, 1 ნიშნავს unhealthy-ს, 2 კი დაცულია და არ უნდა გამოიყენო. პრაქტიკაში Docker ნებისმიერ არანულოვან გასვლას წარუმატებლობად თვლის, მაგრამ დოკუმენტაცია 1-ს ითხოვს, ამიტომ გავრცელებული იდიომა შემოწმებას || exit 1-ით ამთავრებს.
| პარამეტრი | ნაგულისხმევი | რას აკონტროლებს |
|---|---|---|
--interval | 30s | დრო შემოწმებებს შორის გაშვების შემდეგ |
--timeout | 30s | რამდენ ხანს შეიძლება გაგრძელდეს ერთი შემოწმება, სანამ წარუმატებლად ჩაითვლება |
--retries | 3 | მიყოლებითი წარუმატებლობების რაოდენობა unhealthy-ის მისანიჭებლად |
--start-period | 0s | გაშვების შემდგომი საპატიო ფანჯარა, სადაც წარუმატებლობები არ ითვლება |
--start-interval | 5s | დრო შემოწმებებს შორის start period-ის განმავლობაში (Engine 25.0+) |
რამდენიმე დეტალი, რომელიც ცხრილში არ ჩანს:
- Interval ითვლება წინა შემოწმების დასრულებიდან და არა მისი დაწყებიდან. შემოწმება, რომელსაც 4 წამი სჭირდება 30-წამიანი interval-ის დროს, დაახლოებით ყოველ 34 წამში ერთხელ სრულდება.
- Timeout ერთი გაშვების მკაცრი ზღვარია. თუ ბრძანება ვადის გასვლისას ისევ მუშაობს, ეს გაშვება წარუმატებლობაა. ლოკალური HTTP მოთხოვნისთვის 30 წამი ნაგულისხმევად ძალიან ბევრია. თუ
/healthz3-5 წამში არ პასუხობს, რაღაც სწორად არ არის და მეტი ლოდინი პრობლემის აღმოჩენას მხოლოდ აგვიანებს. - Retries მიყოლებით წარუმატებლობებს ითვლის. ერთი წარმატება მთვლელს ნულზე აბრუნებს. შემოწმება, რომელიც ყოველ მეორედ ვარდება,
unhealthy-ს ვერასდროს აღწევს, და ესაა კარგი მიზეზი, რომ შემოწმება დეტერმინისტული გახადო. - Start period პირველ შემოწმებას არ აყოვნებს. შემოწმებები ამ დროს მაინც სრულდება, უბრალოდ მათი წარუმატებლობები არ ითვლება. წარმატება start period-ის განმავლობაში მას ადრევე წყვეტს: კონტეინერი healthy-ა და ყველა შემდგომი წარუმატებლობა უკვე ითვლება.
- Start interval მხოლოდ start period-ის შიგნით მოქმედებს.
start_period: 0s-ის, ანუ ნაგულისხმევის, დროსstart_intervalარაფერს აკეთებს.
რატომ ელოდება პირველი შემოწმება მთელ interval-ს#
სწორედ ეს ქცევაა უმეტესი "ჩემი კონტეინერი starting-ში ჩარჩა" კითხვის მიზეზი. Docker პირველ probe-ს კონტეინერის გაშვებიდან ერთი interval-ის შემდეგ გეგმავს. ის ნულოვან მომენტში არ ამოწმებს, აპი უკვე ხომ არ მუშაობს. სანამ ეს პირველი probe არ წარმატდება, docker ps აჩვენებს (health: starting)-ს.
30-წამიანი ნაგულისხმევის დროს ეს უვნებელია. უვნებელი აღარ არის, როცა ვინმე ასე მსჯელობს: "შემოწმება იაფია, მაგრამ ხშირად არ მჭირდება, ამიტომ interval: 5m". ახლა ყველა ახალი კონტეინერი ხუთი წუთით რჩება starting-ში. ყველა სერვისი, რომელსაც depends_on: condition: service_healthy აქვს, ხუთ წუთს ელოდება, სანამ Compose მას შექმნის. docker compose up --wait კი ხუთი წუთით ბლოკავს deploy-ს, რომელიც ორ წამში იყო მზად. interval: 1h-ის დროს კონტეინერი ერთი საათი არის starting-ში.
Engine 25.0-მდე სუფთა გამოსავალი არ არსებობდა. გრძელი interval ნიშნავდა ნელ პირველ ვერდიქტს, მოკლე interval კი ყოველ რამდენიმე წამში გამუდმებულ polling-ს. ხალხი 10-30 წამს ირჩევდა და ორივე ხარჯს ეგუებოდა.
--start-interval ორივეს ერთმანეთისგან ჰყოფს. start period-ის განმავლობაში Docker ამოწმებს ყოველ start_interval-ში. პირველი წარმატების შემდეგ, ან როცა start period დასრულდება, ის ჩვეულებრივ interval-ზე გადადის. კონტეინერი შეიძლება ჩატვირთვისას ყოველ 2 წამში მოწმდებოდეს, შემდეგ კი ყოველ 5 წუთში:
HEALTHCHECK --interval=5m --timeout=3s --retries=3 \ --start-period=60s --start-interval=2s \ CMD curl -fsS http://127.0.0.1:8080/healthz || exit 1თუ აპი 7 წამის შემდეგ პასუხობს, მეოთხე ან მეხუთე probe წარმატდება და კონტეინერი გაშვებიდან დაახლოებით 8 წამში გახდება healthy, და არა 5 წუთში. თუ აპი საერთოდ არ ამოვიდა, start period 60 წამის შემდეგ ამოიწურება და იქიდან წარუმატებლობები 5-წუთიანი interval-ით ჩაითვლება.
რამდენ ხანში healthy და რამდენ ხანში unhealthy#
ნებისმიერი შემოწმებისთვის ორი რიცხვი ღირს გამოთვლად: რა სისწრაფით გამოცხადდება კარგი კონტეინერი healthy-დ და რამდენად ნელა გამოცხადდება მკვდარი unhealthy-დ.
Healthy-მდე დრო დაახლოებით ჩატვირთვის დროა, მომდევნო probe-მდე დამრგვალებული. start interval-ის გარეშე პირველი probe interval-ზეა, ამიტომ კონტეინერი მასზე ადრე ვერასოდეს გახდება healthy. start interval-ით ეს ჩატვირთვის დროს პლუს მაქსიმუმ ერთ start_interval-ს უდრის.
Unhealthy-მდე დრო აპისთვის, რომელიც healthy-ობის შემდეგ ჩაიკიდა, დაახლოებით retries შემოწმებაა:
worst case ~ retries x (interval + timeout)defaults: 3 x (30s + 30s) = about 3 minutestuned: 3 x (10s + 3s) = about 40 secondsTimeout იმიტომ ითვლება, რომ ჩაკიდებული აპი კავშირს არ აუქმებს. ის მას იღებს და არასდროს პასუხობს, ამიტომ ყოველი probe წარუმატებლობამდე სრულ timeout-ს ხარჯავს. ეს მეორე მიზეზია, რატომ უნდა შეამცირო ნაგულისხმევი timeout: ნაგულისხმევებით ჩაკიდებულ პროცესს სამი წუთის განმავლობაში შეუძლია შეცდომები გასცეს, სანამ Docker რამეს აღიარებს.
აპისთვის, რომელიც საერთოდ არასდროს ხდება healthy, დაამატე start period. მის შიგნით წარუმატებლობები არ ითვლება, ამიტომ პირველი ჩათვლილი წარუმატებლობა start_period-ის შემდეგ მოდის და unhealthy retries probe-ის მერე.
რამდენიმე საწყისი წერტილი, რომელიც შენს აპზე უნდა მოარგო:
| დატვირთვა | Interval / timeout | Start period |
|---|---|---|
| პატარა ვებ-აპი ან API | 30s / 3s | 30s, start interval 2s |
| PostgreSQL ან MySQL | 10s / 5s | 30s-დან 60s-მდე |
| JVM ან .NET აპი | 30s / 5s | 60s-დან 120s-მდე |
| ბაზა, რომელიც პირველ გაშვებაზე dump-ს აღადგენს | 10s / 5s | რამდენიმე წუთი |
retries დატოვე 3-ზე, თუ კონკრეტული მიზეზი არ გაქვს. ერთი წარუმატებლობა ხმაურია. სამი მიყოლებით უკვე კანონზომიერებაა.
Dockerfile-ის სინტაქსი Compose-ის სინტაქსის წინააღმდეგ#
ერთი და იგივე შემოწმება სამ ადგილას შეიძლება ცხოვრობდეს და თითოეულში განსხვავებულად იწერება.
Dockerfile-ში ეს ინსტრუქციაა ფლაგებით და ის image-ის მეტამონაცემების ნაწილი ხდება:
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --start-interval=2s \ --retries=3 CMD ["curl", "-fsS", "http://127.0.0.1:8080/healthz"]Dockerfile-ში მხოლოდ ერთი HEALTHCHECK შეიძლება იყოს. თუ რამდენიმეა, ბოლო იმარჯვებს. საბაზო image-ში არსებული health check მემკვიდრეობით გადადის, HEALTHCHECK NONE კი მას ამორთავს.
Compose-ში ეს სერვისის healthcheck: გასაღებია, სადაც ფლაგების დეფისების ადგილას ქვედა ტირეებია:
services: app: image: example/app:1.4.2 healthcheck: test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/healthz"] interval: 30s timeout: 3s retries: 3 start_period: 30s start_interval: 2sხანგრძლივობები იწერება ასე: 1m30s, 10s ან 500ms. Compose-ის healthcheck image-ში ჩაშენებულს ველი-ველით გადაფარავს, ამიტომ შეგიძლია image-ის ბრძანება დატოვო და მხოლოდ დროითი პარამეტრები შეცვალო. image-ის შემოწმების მთლიანად მოსაშორებლად გამოიყენე disable: true (ან test: ["NONE"]). start_interval Compose-ის ფაილში საჭიროებს Docker Compose 2.20.2-ს ან უფრო ახალს და, Dockerfile-ის ფლაგის მსგავსად, ძალაში შესასვლელად Engine 25.0-ს ან უფრო ახალს.
`docker run`-ზე იგივე პარამეტრები ფლაგებია: --health-cmd, --health-interval, --health-timeout, --health-retries, --health-start-period, --health-start-interval და --no-healthcheck მემკვიდრეობით მიღებულის გასათიშად.
რომელი ადგილია სწორი? შემოწმება Dockerfile-ში ჩადე, როცა ის აპს ეკუთვნის: image-მა იცის თავისი პორტი და health path და ყოველ deployment-ს გონივრული ნაგულისხმევი აქვს. Compose-ში ჩადე, როცა ის deployment-ზეა დამოკიდებული, მაგალითად სხვა პორტი, დამოკიდებულება, რომელსაც შემოწმება უნდა დაელოდოს, ან მესამე მხარის image, რომლის ხელახლა აგება არ შეგიძლია.
CMD და CMD-SHELL და დოლარის ნიშნის ხაფანგი#
test ველი სამ ფორმას იღებს და განსხვავება მნიშვნელოვანია, როგორც კი ბრძანებაში pipe, ცვლადი ან || გამოჩნდება.
["CMD", "curl", "-fsS", "http://127.0.0.1:8080/healthz"]- exec ფორმა. Docker ბინარულ ფაილს უშუალოდ უშვებს, shell-ის გარეშე. pipe-ები,$VAR-ის გაშლა და||არ მუშაობს. ის იმ image-ებშიც მუშაობს, სადაც shell არ არის.["CMD-SHELL", "curl -fsS http://127.0.0.1:8080/healthz || exit 1"]- სტრიქონს კონტეინერის ნაგულისხმევი shell-ით უშვებს, Linux-ზე ეს/bin/sh -c-ა. pipe-ები, ცვლადები და||მუშაობს.test: curl -fsS http://127.0.0.1:8080/healthz || exit 1- ჩვეულებრივი სტრიქონიCMD-SHELL-ის ტოლფასია.
Dockerfile-შიც იგივე დაყოფა არსებობს: HEALTHCHECK CMD ["curl", ...] exec ფორმაა, HEALTHCHECK CMD curl ... || exit 1 კი shell ფორმა.
ხაფანგი Compose-ში ცვლადებია. Compose $VAR-ს თავად ანაცვლებს შენი shell-იდან და .env ფაილიდან, სანამ კონტეინერი მას დაინახავს. შემოწმება, რომელიც ასე წერია: pg_isready -U $POSTGRES_USER, მნიშვნელობას იმ მანქანიდან იღებს, სადაც docker compose მუშაობს, და ის ხშირად ცარიელია. რომ კონტეინერის shell-მა გახსნას, დოლარის ნიშანი გააორმაგე:
db: image: postgres:17 environment: POSTGRES_USER: app POSTGRES_PASSWORD_FILE: /run/secrets/db_password healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5 start_period: 30s start_interval: 2s$$ კონტეინერამდე ერთ $-ად აღწევს. კონტეინერის გარემო POSTGRES_USER-ს მართლაც შეიცავს, რადგან health check-ები კონტეინერის გარემოთი სრულდება, ზუსტად docker exec-ივით.
კიდევ ორი რამ იმის შესახებ, სად სრულდება შემოწმება. ის კონტეინერის შიგნით სრულდება, ამიტომ localhost თავად კონტეინერია და არა ჰოსტი. აპის შესამოწმებლად ეს სწორია, მაგრამ ნიშნავს, რომ health check არასდროს ამოწმებს გამოქვეყნებულ პორტს ან წინ მდგომ proxy-ს. და localhost-ის ნაცვლად ამჯობინე 127.0.0.1: ზოგ image-ზე localhost ჯერ IPv6 ::1-ზე გადადის, 0.0.0.0-ზე მიბმული აპი (მხოლოდ IPv4) კავშირს უარყოფს და შემოწმება ვარდება, თუმცა აპი ჯანსაღია.
როცა image-ში curl ან wget არ არის#
ზემოთ მოყვანილი მაგალითები curl-ს ვარაუდობს, მრავალ image-ს კი ის არ აქვს. Slim და მინიმალური image-ები ყველაფერს გამოტოვებს, რაც აპს არ სჭირდება: node:22-slim-სა და python:3.13-slim-ს არც curl აქვთ და არც wget. Alpine-ზე დაფუძნებულ image-ებს BusyBox-ის wget აქვთ, მაგრამ curl არა. Distroless image-ებს shell-იც არ აქვთ, ამიტომ ნებისმიერი CMD-SHELL შემოწმება დაწყებამდე ვარდება. შემოწმება, რომელსაც თავისი ბინარული ფაილი ვერ პოულობს, ყოველთვის ვარდება და კონტეინერი unhealthy ხდება, მაშინ როცა აპი სრულიად კარგადაა. docker inspect შემდეგ health log-ში აჩვენებს curl: not found-ს ან exec-ის შეცდომას.
სამი გზა არსებობს.
- დააყენე ხელსაწყო.
curl-ის დამატება Debian slim image-ში ერთიapt-get installხაზია და რამდენიმე მეგაბაიტი. ეს ხშირად მისაღებია, მაგრამ image-ის შეტევის ზედაპირს ერთი probe-სთვის პაკეტს უმატებს. - გამოიყენე ის, რაც უკვე არის. Alpine-ზე BusyBox-ის
wgetმუშაობს:wget -q --spider http://127.0.0.1:8080/healthz || exit 1. მონაცემთა ბაზებს საკუთარი probe-ები მოჰყვებათ:pg_isreadyPostgres image-ში,mysqladmin pingMySQL-ში. - გამოიყენე runtime, რომელიც უკვე გაქვს. Node image-ს Node აქვს, Python image-ს Python. ორივეს შეუძლია HTTP მოთხოვნის გაგზავნა ერთ ხაზში.
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --start-interval=2s \ CMD ["node", "-e", "fetch('http://127.0.0.1:3000/healthz').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --start-interval=2s \ CMD ["python", "-c", "import urllib.request,sys; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=2)"]Python-ის ვერსია მუშაობს, რადგან urlopen ნებისმიერ 4xx ან 5xx სტატუსზე და უარყოფილ კავშირზე გამონაკლისს ისვრის, დაუჭერელი გამონაკლისი კი სტატუსით 1 სრულდება. ორივე exec ფორმაა, ამიტომ shell-ის გარეშე image-ებზეც მუშაობს. Node-ის ან Python-ის ინტერპრეტატორის გაშვება curl-ზე ძვირი ჯდება, წამიერად ათობით მეგაბაიტი. 30-წამიანი interval-ის დროს ეს უმნიშვნელოა, პატარა მანქანაზე 2-წამიანი start interval-ის დროს კი ფიქრად ღირს.
distroless image-ებისთვის ყველაზე სუფთა პასუხი image-ში ჩაშენებული პატარა health-check ბინარული ფაილია, ან შენს აპში --health რეჟიმი, რომელიც მოთხოვნას აგზავნის და გადის. ბევრი Go სერვისი ზუსტად ამას აკეთებს.
რა ხელსაწყოსაც არ უნდა იყენებდე, გააკეთე ისე, რომ HTTP შეცდომაზე ვარდებოდეს და არა მხოლოდ უარყოფილ კავშირზე. უბრალო curl 500 პასუხზე 0-ით გადის. -f (--fail) არის ის, რაც შეცდომის სტატუსს არანულოვან გასვლად აქცევს. მის გარეშე შემოწმება მხოლოდ იმას ადასტურებს, რომ რაღაც უსმენს.
depends_on და service_healthy#
Health სტატუსი ყველაზე მნიშვნელოვანია Compose-ის გაშვების თანმიმდევრობისთვის. დამოკიდებულება, რომელიც condition: service_healthy-ითაა გამოცხადებული, დამოკიდებულ სერვისს აჩერებს, სანამ დამოკიდებულება healthy-ს არ დააფიქსირებს:
app: image: example/app:1.4.2 depends_on: db: condition: service_healthy restart: trueაქ ანაზღაურდება interval-ის მორგება. Compose ბაზის პირველ წარმატებულ probe-ს ელოდება, ამიტომ ბაზა interval: 60s-ით და start interval-ის გარეშე ყოველ up-ზე აპს მინიმუმ ერთი წუთით აგვიანებს, რაც სწრაფადაც არ უნდა ჩაიტვირთოს Postgres. start_interval: 2s-ით აპი ბაზის მზადყოფნიდან რამდენიმე წამში იწყება.
Compose ასევე თავს ანებებს, თუ დამოკიდებულება unhealthy გახდა: up ვარდება შეტყობინებით, რომ დამოკიდებულების გაშვება ვერ მოხერხდა. ჩვეულებრივ start period პირველი გაშვებისთვის ძალიან მოკლე იყო, მაგალითად როცა ბაზა ახალ volume-ს ინიციალიზებს ან dump-ს აღადგენს, შემდგომი გადატვირთვები კი რიგზე იყო. გააგრძელე start period და არა retries, რომ საპატიო დრო მხოლოდ ჩატვირთვისას მოქმედებდეს.
restart: true (Compose 2.17.0 ან უფრო ახალი) დამოკიდებულ სერვისს რესტარტავს, როცა თავად Compose რესტარტავს ან ანახლებს დამოკიდებულებას. ეს health-ზე დაფუძნებული რესტარტი არ არის. ბაზა, რომელიც თავისით ხდება unhealthy, არაფერს იწვევს.
docker compose up --wait იგივე სიგნალს deploy-ებისთვის იყენებს: ის მაშინ ბრუნდება, როცა ყველა სერვისი გაშვებულია და healthy, და არანულოვანი კოდით გადის, თუ რომელიმე ვარდება. deploy სკრიპტში სწორედ ეს გაძლევს საშუალებას, ტრაფიკის გადართვამდე შეჩერდე და არა მის შემდეგ. Zero-downtime deploy-ები პატარა სერვერზე ზუსტად ამ ლოდინზეა აგებული.
Health log-ის კითხვა docker inspect-ით#
docker ps შეჯამებას სტატუსის სვეტში აჩვენებს: Up 2 minutes (healthy), (health: starting) ან (unhealthy). ჰოსტზე ყველა unhealthy კონტეინერის საპოვნელად:
$ docker ps --filter health=unhealthy$ docker inspect --format '{{json .State.Health}}' app | python3 -m json.toolHealth ობიექტი შეიცავს Status-ს, FailingStreak-ს (ამ დროისთვის მიყოლებითი წარუმატებლობები) და Log-ს, უახლესი probe-ების შედეგების სიას. თითოეულ ჩანაწერს აქვს Start, End, ExitCode და Output. Docker მხოლოდ ბოლო ხუთ შედეგს ინახავს და თითოეული შემოწმების გამოსავლის მხოლოდ პირველ 4096 ბაიტს. ამიტომ health endpoint, რომელიც წარუმატებლობისას მოკლე მიზეზს ბეჭდავს (db: connection refused), აქ გაცილებით სასარგებლოა, ვიდრე ის, რომელიც stack trace-ს გამოყრის.
რამის შეცვლამდე წაიკითხე Output. გავრცელებული შეტყობინებები და მათი მნიშვნელობა:
curl: not found,executable file not found in $PATH- ხელსაწყო image-ში არ არის. იხილე წინა განყოფილება.Health check exceeded timeout- ბრძანება დროზე ვერ დასრულდა. ან აპია ჩაკიდებული, ან timeout კანონიერი ნელი პასუხისთვის ძალიან მოკლეა.Connection refused- კონტეინერის შიგნით ამ მისამართზე არავინ უსმენს. შეამოწმე პორტი და შეადარე127.0.0.1localhost-ს.- HTTP
503შენივე endpoint-იდან - შემოწმება მუშაობს და აპი რეალურ პრობლემას აცხადებს. გაასწორე აპი და არა შემოწმება.
გადასვლების თვალყურის დევნებაც შეგიძლია რეალურ დროში ბრძანებით docker events --filter event=health_status, რომელიც ხაზს ბეჭდავს ყოველ ჯერზე, როცა კონტეინერი healthy-სა და unhealthy-ს შორის გადადის.
Unhealthy არაფერს არ რესტარტავს#
Docker-ის restart policy-ები (no, on-failure, always, unless-stopped) მხოლოდ კონტეინერის მთავარი პროცესის გასვლაზე რეაგირებენ და სხვაზე არაფერზე. unhealthy კონტეინერი, რომლის პროცესიც ჯერ კიდევ მუშაობს, ზუსტად ისეთივე რჩება, როგორიც იყო, და ტრაფიკსაც აგრძელებს, თუ ადრე იღებდა. Health სტატუსი ინფორმაციაა. უბრალო Docker და Compose მას აჩვენებენ და მხოლოდ გაშვებისას მოქმედებენ მასზე, depends_on-ისა და --wait-ის მეშვეობით.
სამი რამ მასზე მაინც რეაგირებს:
- Docker Swarm ცვლის სერვისის task-ებს, რომლებიც unhealthy ხდება. თუ Swarm-ს იყენებ, health check რეალური რესტარტის გამშვებია.
- Watcher, რომელსაც თავად დაამატებ. პატარა კონტეინერი Docker socket-ზე წვდომით
unhealthy-ს ეძებს და რასაც იპოვის, რესტარტავს. ცნობილი მაგალითიაwillfarrell/autohealimage. Docker socket-ის მიმაგრება ამ კონტეინერს ჰოსტზე root-ის ტოლფას კონტროლს აძლევს, ამიტომ ის ისე მოეკიდე, როგორც კომპრომისს. - აპის თავისით გასვლა. თუ აპს შეუძლია აღმოაჩინოს, რომ გაფუჭებულია, არანულოვანი სტატუსით გასვლა ყველაზე საიმედო რესტარტის გამშვებია, რადგან ყველა restart policy მას ესმის.
Kubernetes გამონაკლისია, რომელზეც ხალხი წაიფორხილებს: ის Dockerfile-ის HEALTHCHECK-ს სრულიად უგულებელყოფს და საკუთარ liveness, readiness და startup probe-ებს იყენებს. startupProbe იქ start period-ის როლს ასრულებს.
ფრთხილად იყავი, რას ნატრობ ავტომატური რესტარტებისგან. შემოწმება, რომელიც იმიტომ ვარდება, რომ ბაზა გათიშულია, ჯანსაღ აპს ციკლში გადატვირთავს, რასაც graceful shutdown-ის პოსტი გამაძლიერებელს უწოდებს. რაც health-ზე რესტარტდება, მხოლოდ იმას უნდა უყურებდეს, რისი გამოსწორებაც რესტარტს შეუძლია. და დააყენე alert health სტატუსის ცვლილებაზე, როგორც ამას მონიტორინგი, რომელიც რაღაცას გეუბნება აღწერს, ნაცვლად იმისა, რომ ჩუმად გადაფაროს.
RE:NODE-ის აპ პლანებზე საქმე ცოტა სხვაგვარადაა. თითოეული სერვერი კონტეინერია, რომელსაც ჩვენ ვმართავთ, შენი Docker daemon-ის გარეშე, ამიტომ მოსარგებად HEALTHCHECK არ არსებობს. სამაგიეროდ, crash watcher ყოველ ორ წუთში ამოწმებს, ხომ არ დაბრუნდა uptime უკან ან სერვერი ხომ არ გაითიშა, და რესტარტები, რომლებიც შენ მოითხოვე, არ ითვლება. ერთ საათში სამი დაუგეგმავი რესტარტი სერვერის გვერდზე გაფრთხილებას აჩენს და ticket იხსნება. ექვსი სერვერს აჩერებს. ამიტომ ფატალურ შეცდომაზე გასვლა იქაც სწორი დიზაინია. თუ Docker-ის საკუთარი health მექანიზმი გინდა Compose-თან და service_healthy-თან ერთად, ამას მანქანა სჭირდება, სადაც daemon შენია, და ამისთვისაა VDS ხაზი. Docker VDS-ზე მოწყობას აღწერს.
FAQ#
რატომ ჩარჩა ჩემი კონტეინერი "health: starting"-ში?
პირველი probe ჯერ არ წარმატებულა. ან პირველი შემოწმება მხოლოდ მთელი ერთი interval-ის შემდეგ ხდება (ამიტომ გრძელი interval გრძელ ლოდინს ნიშნავს), ან ყველა ამჟამინდელი შემოწმება start period-ის შიგნით ჩავარდა, სადაც წარუმატებლობები არ ითვლება. გაუშვი კონტეინერზე docker inspect --format '{{json .State.Health}}'. ცარიელი Log ნიშნავს, რომ ჯერ არც ერთი შემოწმება არ გაშვებულა. არანულოვანი გასვლის კოდის მქონე ჩანაწერები ნიშნავს, რომ შემოწმება ვარდება და Output ამბობს, რატომ.
რა არის კარგი Docker healthcheck interval?
ტიპური ვებ სერვისისთვის 30 წამი 3-წამიანი timeout-ითა და 3 retries-ით, რაც ჩაკიდებულ აპს ორ წუთზე ნაკლებ დროში აღნიშნავს. უფრო მოკლე მხოლოდ მაშინ აირჩიე, თუ რაღაც შედეგზე სწრაფად რეაგირებს, მაგალითად load balancer ან Swarm. Engine 25.0-ზე ან უფრო ახალზე ნებისმიერ ერთ წუთზე გრძელ interval-ს დაუწყვილე start_period და რამდენიმე წამის start_interval, რომ გაშვება გრძელ interval-ს არ დაელოდოს.
აყოვნებს თუ არა start_period პირველ health check-ს?
არა. შემოწმებები start period-ის განმავლობაში ჩვეულებრივი interval-ით სრულდება, ან start_interval-ით Engine 25.0-ზე და უფრო ახალზე. ფანჯრის შიგნით წარუმატებლობები უბრალოდ retries-ში არ ითვლება. პირველი წარმატება start period-ს ადრევე წყვეტს.
რესტარტავს თუ არა Docker unhealthy კონტეინერს?
თავისით არა. restart policy-ები მხოლოდ მაშინ მოქმედებს, როცა მთავარი პროცესი გადის. Swarm სერვისები, watcher, მაგალითად autoheal, ან აპის თავისით გასვლა არის გზები, რომლებითაც unhealthy რესტარტად იქცევა. Compose health-ს მხოლოდ გაშვების თანმიმდევრობისთვის და up --wait-ისთვის იყენებს.
უნდა მიმართოს თუ არა health check-მა ბაზას?
ჩვეულებრივ არა, თუ შემოწმებაზე რამე რესტარტდება. ბაზის მოკლე შეფერხება ყველა აპის კონტეინერს ერთდროულად unhealthy-დ მონიშნავდა. შეამოწმე თავად პროცესი და დამოკიდებულებები ცალკე readiness endpoint-ით გამოაცხადე. თავად ბაზის კონტეინერისთვის შემოწმება, რა თქმა უნდა, ბაზის საკუთარი probe უნდა იყოს, მაგალითად pg_isready ან mysqladmin ping.
შემიძლია თუ არა health check-ის შეცვლა image-ის ხელახლა აგების გარეშე?
დიახ. healthcheck: ბლოკი Compose-ში ან --health-* ფლაგები docker run-ზე image-ის მნიშვნელობებს გადაფარავს, disable: true ან --no-healthcheck კი მას ამორთავს. Dockerfile-ის ინსტრუქცია მხოლოდ ნაგულისხმევია.


