Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд

Kubernetes-д CI/CD-г хэрэгжүүлэх ердийн нөхцөл: програм нь бүрэн зогсоохоос өмнө шинэ үйлчлүүлэгчийн хүсэлтийг хүлээж авахгүй байх ёстой бөгөөд хамгийн чухал нь одоо байгаа хүсэлтийг амжилттай дуусгах ёстой.

Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд

Энэ нөхцлийг дагаж мөрдөх нь ашиглалтын явцад тэг зогсолт хийх боломжийг танд олгоно. Гэсэн хэдий ч, маш алдартай багцуудыг (NGINX болон PHP-FPM гэх мэт) ашиглаж байсан ч суулгалт бүрт алдаа гарахад хүргэдэг бэрхшээлүүд тулгарч магадгүй юм...

Онол. Под хэрхэн амьдардаг

Подгоны амьдралын мөчлөгийн талаар бид аль хэдийн дэлгэрэнгүй нийтэлсэн энэ нийтлэл. Хэлэлцэж буй сэдвийн хүрээнд бид дараахь зүйлийг сонирхож байна: pod нь мужид орох үед Дуусгах, шинэ хүсэлтүүд түүн рүү илгээгдэхээ больсон (pod хасагдсан үйлчилгээний эцсийн цэгүүдийн жагсаалтаас). Тиймээс, байршуулах явцад сул зогсолт гарахаас зайлсхийхийн тулд програмыг зогсоох асуудлыг зөв шийдвэрлэхэд хангалттай.

Та мөн үндсэн хөнгөлөлтийн хугацаа гэдгийг санах хэрэгтэй 30 секунд: үүний дараа pod ажиллахгүй бөгөөд энэ хугацаанаас өмнө програм бүх хүсэлтийг боловсруулах цагтай байх ёстой. тайлбар: Хэдийгээр 5-10 секундээс илүү хугацаа шаардагддаг аливаа хүсэлт нь аль хэдийн асуудалтай байгаа бөгөөд гоёмсог унтрах нь цаашид тус болохгүй...

Под дуусах үед юу болохыг илүү сайн ойлгохын тулд дараах диаграмыг харна уу.

Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд

A1, B1 - Зуухны төлөв байдлын талаархи өөрчлөлтийг хүлээн авах
A2 - Хөдлөх SIGTERM
B2 - Төгсгөлийн цэгүүдээс хонхорцог арилгах
B3 - Өөрчлөлтийг хүлээн авах (төгсгөлийн цэгүүдийн жагсаалт өөрчлөгдсөн)
B4 - iptables дүрмийг шинэчлэх

Анхаарна уу: төгсгөлийн цэгийг устгаж, SIGTERM илгээх нь дараалсан биш, харин зэрэгцээ явагддаг. Ingress нь Төгсгөлийн цэгүүдийн шинэчилсэн жагсаалтыг шууд хүлээн авахгүй байгаа тул үйлчлүүлэгчдээс ирсэн шинэ хүсэлтийг подк руу илгээх бөгөөд энэ нь pod дуусгах үед 500 алдаа гаргах болно. (энэ асуудлын талаархи дэлгэрэнгүй материалыг бид орчуулсан). Энэ асуудлыг дараах байдлаар шийдвэрлэх шаардлагатай.

  • Холболт илгээх: хариултын толгой хэсгийг хаах (хэрэв энэ нь HTTP програмтай холбоотой бол).
  • Хэрэв кодонд өөрчлөлт оруулах боломжгүй бол хөнгөлөлттэй хугацаа дуустал хүсэлтийг боловсруулах боломжийг танд олгох шийдлийг дараах нийтлэлд тайлбарласан болно.

Онол. NGINX болон PHP-FPM хэрхэн процессоо зогсоодог

NGINX

NGINX-ээс эхэлцгээе, учир нь үүн дээр бүх зүйл тодорхой харагдаж байна. Онол руу ороход бид NGINX нь нэг мастер процесс, хэд хэдэн "ажилчид"-тай болохыг олж мэдсэн - эдгээр нь үйлчлүүлэгчийн хүсэлтийг боловсруулдаг хүүхдийн процессууд юм. Тохиромжтой сонголтыг өгсөн: командыг ашиглан nginx -s <SIGNAL> хурдан унтрах эсвэл гоёмсог унтрах горимд процессуудыг дуусгах. Мэдээжийн хэрэг, энэ нь бидний сонирхлыг татдаг сүүлчийн хувилбар юм.

Дараа нь бүх зүйл энгийн: та нэмэх хэрэгтэй preStop-дэгээ сайхан унтраах дохио илгээх тушаал. Үүнийг контейнерийн блок дотор байршуулах хэсэгт хийж болно:

       lifecycle:
          preStop:
            exec:
              command:
              - /usr/sbin/nginx
              - -s
              - quit

Одоо, pod унтрах үед бид NGINX контейнерийн бүртгэлд дараах зүйлийг харах болно.

2018/01/25 13:58:31 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down
2018/01/25 13:58:31 [notice] 11#11: gracefully shutting down

Энэ нь бидэнд хэрэгтэй гэсэн үг юм: NGINX хүсэлтийг дуусгахыг хүлээж, дараа нь процессыг устгадаг. Гэсэн хэдий ч доор бид командтай ч гэсэн нийтлэг асуудлыг авч үзэх болно nginx -s quit үйл явц буруу дуусгавар болно.

Энэ үе шатанд бид NGINX-тэй ажиллаж байна: наад зах нь бүртгэлээс та бүх зүйл зохих ёсоор ажиллаж байгааг ойлгож болно.

PHP-FPM-тэй ямар холбоотой вэ? Энэ нь гоёмсог унтрах асуудлыг хэрхэн зохицуулдаг вэ? Үүнийг олж мэдье.

PHP-FPM

PHP-FPM-ийн хувьд мэдээлэл арай бага байна. Хэрэв та анхаарлаа төвлөрүүлбэл албан ёсны гарын авлага PHP-FPM-ийн дагуу дараах POSIX дохиог хүлээн авсан гэж хэлэх болно.

  1. SIGINT, SIGTERM - хурдан унтрах;
  2. SIGQUIT - гоёмсог унтрах (бидэнд хэрэгтэй зүйл).

Үлдсэн дохио нь энэ даалгаварт шаардлагагүй тул бид тэдгээрийн шинжилгээг орхих болно. Процессыг зөв дуусгахын тулд та дараах preStop дэгээг бичих хэрэгтэй.

        lifecycle:
          preStop:
            exec:
              command:
              - /bin/kill
              - -SIGQUIT
              - "1"

Өнгөц харахад энэ нь хоёр саванд гоёмсог унтрахад шаардлагатай бүх зүйл юм. Гэсэн хэдий ч даалгавар нь санагдахаас илүү хэцүү байдаг. Доорх хоёр тохиолдлыг гоёмсог унтрах нь үр дүнд хүрээгүй бөгөөд байршуулах явцад төслийг богино хугацаанд ашиглах боломжгүй болгосон.

Дасгал хийх. Гоёмсог унтрахтай холбоотой болзошгүй асуудлууд

NGINX

Юуны өмнө үүнийг санах нь зүйтэй: тушаалыг гүйцэтгэхээс гадна nginx -s quit Анхаарал татахуйц өөр нэг үе шат байна. Бидэнд NGINX нь SIGQUIT дохионы оронд SIGTERM-г илгээсэн хэвээр байгаа тул хүсэлтийг буруу бөглөхөд хүргэсэн асуудал тулгарлаа. Үүнтэй төстэй тохиолдлуудыг олж болно, жишээлбэл, энд. Харамсалтай нь бид энэ зан үйлийн тодорхой шалтгааныг тодорхойлж чадаагүй: NGINX хувилбарын талаар сэжигтэй байсан ч энэ нь батлагдаагүй. Үүний шинж тэмдэг нь NGINX контейнерийн бүртгэлд мессеж ажиглагдсан: "10 холболтод үлдсэн №5 залгуурыг нээ", үүний дараа pod зогссон.

Бид ийм асуудлыг ажиглаж болно, жишээлбэл, бидэнд хэрэгтэй Ingress дээрх хариултуудаас:

Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд
Байршуулах үеийн статус кодын үзүүлэлтүүд

Энэ тохиолдолд бид Ingress-ээс ердөө 503 алдааны код хүлээн авдаг: энэ нь NGINX контейнерт хандах боломжгүй тул нэвтрэх боломжгүй. Хэрэв та NGINX-тэй контейнерийн бүртгэлийг харвал тэдгээр нь дараахь зүйлийг агуулна.

[alert] 13939#0: *154 open socket #3 left in connection 16
[alert] 13939#0: *168 open socket #6 left in connection 13

Зогсоох дохиог өөрчилсний дараа сав зөв зогсоож эхэлдэг: энэ нь 503 алдаа ажиглагдахгүй байгаагаар нотлогддог.

Хэрэв та үүнтэй төстэй асуудалтай тулгарвал саванд ямар зогсоох дохиог ашигладаг, мөн preStop дэгээ нь яг ямар байхыг олж мэдэх нь зүйтэй юм. Шалтгаан нь яг үүнтэй холбоотой байж магадгүй юм.

PHP-FPM... болон бусад

PHP-FPM-тэй холбоотой асуудлыг өчүүхэн байдлаар тайлбарласан: энэ нь хүүхдийн процессуудыг дуусгахыг хүлээхгүй бөгөөд энэ нь тэдгээрийг зогсоодог тул байршуулах болон бусад үйлдлүүдийн явцад 502 алдаа гардаг. 2005 оноос хойш bugs.php.net дээр хэд хэдэн алдааны тайлан гарсан (жишээ нь энд и энд), энэ асуудлыг тайлбарладаг. Гэхдээ та бүртгэлээс юу ч харахгүй байх магадлалтай: PHP-FPM нь ямар ч алдаа, гуравдагч этгээдийн мэдэгдэлгүйгээр үйл явц дууссаныг зарлах болно.

Асуудал нь өөрөө програмаас бага эсвэл их хэмжээгээр шалтгаалж болох бөгөөд жишээлбэл, хяналт тавихад илрэхгүй байж болохыг тодруулах нь зүйтэй. Хэрэв та ийм асуудалтай тулгарвал хамгийн түрүүнд энгийн арга зам санаанд орж ирнэ: preStop дэгээ нэмнэ үү sleep(30). Энэ нь танд өмнө нь байсан бүх хүсэлтийг биелүүлэх боломжийг олгоно (мөн бид шинийг хүлээн авахгүй, учир нь pod аль хэдийн чадвартай Дуусгах), 30 секундын дараа pod өөрөө дохиогоор дуусна SIGTERM.

Энэ нь lifecycle савны хувьд дараах байдлаар харагдах болно.

    lifecycle:
      preStop:
        exec:
          command:
          - /bin/sleep
          - "30"

Гэсэн хэдий ч 30 секундын улмаас sleep бид байна их юм Под бүрийг дуусгах тул бид байршуулах хугацааг нэмэгдүүлэх болно хамгийн бага 30 секунд, энэ нь муу. Энэ талаар юу хийж болох вэ?

Өргөдлийн шууд гүйцэтгэлийг хариуцдаг талдаа хандъя. Манай тохиолдолд ийм байна PHP-FPM, энэ нь анхдагчаар нь өөрийн хүүхэд процессуудын гүйцэтгэлийг хянадаггүй: Мастер процесс нэн даруй дуусгавар болно. Та удирдамжийг ашиглан энэ зан үйлийг өөрчилж болно process_control_timeout, энэ нь хүүхдийн процессуудын мастераас дохио хүлээх хугацааг зааж өгдөг. Хэрэв та утгыг 20 секунд гэж тохируулбал энэ нь саванд ажиллаж байгаа ихэнх асуулгад хамрагдах бөгөөд дууссаны дараа мастер процессыг зогсооно.

Энэ мэдлэгээр сүүлчийн асуудал руугаа буцъя. Дээр дурдсанчлан, Кубернетес бол цул платформ биш: түүний өөр өөр бүрэлдэхүүн хэсгүүдийн хоорондын харилцаа холбоо бага зэрэг хугацаа шаарддаг. Энэ нь ялангуяа Ingresses болон бусад холбогдох бүрэлдэхүүн хэсгүүдийн ажиллагааг авч үзэхэд үнэн юм, учир нь байршуулах үед ийм саатал гарсан тул 500 алдаа гарахад хялбар байдаг. Жишээлбэл, хүсэлтийг дээд тал руу илгээх үе шатанд алдаа гарч болзошгүй боловч бүрэлдэхүүн хэсгүүдийн харилцан үйлчлэлийн "цаг хугацааны хоцрогдол" нь нэлээд богино буюу нэг секундээс бага байдаг.

Тиймээс, Нийтдээ аль хэдийн дурдсан удирдамжийн дагуу process_control_timeout Та дараах бүтээн байгуулалтыг ашиглаж болно lifecycle:

lifecycle:
  preStop:
    exec:
      command: ["/bin/bash","-c","/bin/sleep 1; kill -QUIT 1"]

Энэ тохиолдолд бид хоцролтыг командаар нөхөх болно sleep мөн байршуулах хугацааг нэг их нэмэгдүүлэх хэрэггүй: 30 секунд ба нэг секундын хооронд мэдэгдэхүйц ялгаа байна уу?.. Үнэндээ энэ нь process_control_timeoutболон lifecycle хоцрогдсон тохиолдолд зөвхөн “аюулгүйн тор” болгон ашигладаг.

Ерөнхийдөө, тайлбарласан зан төлөв болон холбогдох арга зам нь зөвхөн PHP-FPM-д хамаарахгүй. Бусад хэл/хүрээ ашиглах үед ижил төстэй нөхцөл байдал нэг талаараа үүсч болно. Хэрэв та ухаалаг унтрах асуудлыг өөр аргаар засах боломжгүй бол, жишээлбэл, програм дуусгах дохиог зөв боловсруулахын тулд кодыг дахин бичих замаар та тайлбарласан аргыг ашиглаж болно. Энэ нь хамгийн үзэсгэлэнтэй биш байж болох ч энэ нь ажилладаг.

Дасгал хийх. Подлогын ажиллагааг шалгахын тулд туршилтыг ачаална уу

Ачааллын туршилт нь чингэлэг хэрхэн ажилладагийг шалгах арга замуудын нэг юм, учир нь энэ журам нь хэрэглэгчид сайтад зочлох үед түүнийг жинхэнэ байлдааны нөхцөлд ойртуулдаг. Дээрх зөвлөмжийг туршихын тулд та ашиглаж болно Yandex.Tankom: Энэ нь бидний бүх хэрэгцээг төгс хангадаг. Дараахь зүйл бол Grafana болон Yandex.Tank-ийн графикуудын ачаар бидний туршлагаас тодорхой жишээгээр туршилт хийх зөвлөмж, зөвлөмж юм.

Энд хамгийн чухал зүйл бол өөрчлөлтүүдийг алхам алхмаар шалгана. Шинэ засвар нэмсний дараа тестийг ажиллуулж, үр дүн нь сүүлийн гүйлттэй харьцуулахад өөрчлөгдсөн эсэхийг харна уу. Үгүй бол үр дүнгүй шийдлүүдийг тодорхойлоход хэцүү байх бөгөөд урт хугацаанд энэ нь зөвхөн хор хөнөөл учруулж болзошгүй (жишээлбэл, байршуулах хугацааг нэмэгдүүлэх).

Өөр нэг нюанс бол түүнийг дуусгах явцад савны бүртгэлийг харах явдал юм. Гэнэтийн унтрах тухай мэдээлэл тэнд бүртгэгдсэн үү? Бусад эх сурвалжид (жишээлбэл, хөрш зэргэлдээх PHP-FPM контейнер руу) хандах үед бүртгэлд ямар нэгэн алдаа гарсан уу? Програмын алдаа (дээр тайлбарласан NGINX-тэй адил)? Энэ нийтлэлийн танилцуулга нь савыг дуусгахад юу тохиолдохыг илүү сайн ойлгоход тусална гэж найдаж байна.

Тиймээс анхны туршилтын гүйлт ямар ч байсангүй lifecycle мөн програмын серверт зориулсан нэмэлт зааваргүй (process_control_timeout PHP-FPM дээр). Энэ туршилтын зорилго нь ойролцоогоор алдааны тоог (болон байгаа эсэхийг) тодорхойлох явдал байв. Нэмэлт мэдээллээс харахад pod тус бүрийн ашиглалтын дундаж хугацаа нь бүрэн бэлэн болтол ойролцоогоор 5-10 секунд байсан гэдгийг та мэдэх ёстой. Үр дүн нь:

Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд

Yandex.Tank мэдээллийн самбарт 502 алдаа гарсан бөгөөд энэ нь байршуулах үед гарсан бөгөөд дунджаар 5 секунд хүртэл үргэлжилсэн. Энэ нь хуучин pod-д байсан хүсэлтүүд нь цуцлагдах үед дуусгавар болж байсантай холбоотой байх. Үүний дараа 503 алдаа гарсан бөгөөд энэ нь NGINX контейнер зогссоны үр дүн байсан бөгөөд энэ нь арын хэсгийн улмаас холболтыг тасалсан (энэ нь Ingress-ийг холбогдохоос сэргийлсэн).

Хэрхэн гэдгийг харцгаая process_control_timeout PHP-FPM-д хүүхдийн процесс дуусахыг хүлээхэд бидэнд туслах болно, жишээлбэл. ийм алдаануудыг засна. Энэ удирдамжийг ашиглан дахин байрлуулна уу:

Kubernetes-ийн зөвлөмж, заль мэх: NGINX болон PHP-FPM-ийн гайхалтай унтрах онцлогууд

500 дахь байршуулалтын явцад дахин алдаа гарахгүй! Байршлуулалт амжилттай болж, унтрах ажиллагаа амжилттай боллоо.

Гэсэн хэдий ч цаг хугацааны хоцрогдолтой холбоотой алдааны багахан хувийг эзэлдэг Ingress контейнертэй холбоотой асуудлыг санах нь зүйтэй. Тэднээс зайлсхийхийн тулд зөвхөн бүтэц нэмэхэд л үлддэг sleep мөн байршуулалтыг давт. Гэсэн хэдий ч бидний онцгой тохиолдолд ямар ч өөрчлөлт харагдахгүй (дахин алдаа байхгүй).

дүгнэлт

Процессыг аятайхан дуусгахын тулд бид програмаас дараах үйлдлийг хүлээж байна:

  1. Хэдэн секунд хүлээгээд шинэ холболтыг хүлээн авахаа зогсоо.
  2. Бүх хүсэлтийг дуусгахыг хүлээж, хүсэлтийг биелүүлээгүй бүх амьд холболтыг хаах хэрэгтэй.
  3. Процессоо дуусга.

Гэсэн хэдий ч бүх програмууд ийм байдлаар ажиллах боломжгүй. Кубернетес бодит байдлын асуудлын нэг шийдэл нь:

  • хэдэн секунд хүлээх болно урьдчилан зогсоох дэгээ нэмэх;
  • Тохирох параметрүүдийг манай арын хэсгийн тохиргооны файлыг судалж байна.

NGINX-ийн жишээнээс харахад дуусгах дохиог зөв боловсруулах ёстой програм ч үүнийг хийхгүй байж болох тул програмыг байршуулах явцад 500 алдаа байгаа эсэхийг шалгах нь маш чухал юм. Энэ нь мөн асуудлыг илүү өргөн хүрээнд авч үзэх боломжийг олгодог бөгөөд нэг под, контейнер дээр төвлөрөхгүй, харин бүхэл бүтэн дэд бүтцийг авч үзэх боломжийг олгодог.

Туршилтын хэрэгсэл болгон та Yandex.Tank-ийг ямар ч хяналтын системтэй хамт ашиглаж болно (бидний тохиолдолд туршилтанд зориулж Prometheus backend бүхий Grafana-аас өгөгдлийг авсан). Хяналттай унтрахтай холбоотой асуудлууд нь жишиг үзүүлэлт үүсгэж болох хүнд ачааллын дор тодорхой харагддаг бөгөөд хяналт нь туршилтын явцад эсвэл дараа нь нөхцөл байдлыг илүү нарийвчлан шинжлэхэд тусалдаг.

Нийтлэлийн талаархи санал хүсэлтийн хариуд: NGINX Ingress-тэй холбоотой асуудал, шийдлүүдийг энд тайлбарласан гэдгийг дурдах нь зүйтэй. Бусад тохиолдолд бусад шийдлүүд байдаг бөгөөд бид үүнийг цувралын дараах материалд авч үзэх болно.

PS

K8-ийн бусад зөвлөмж, аргачлалын цувралууд:

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх