Kubernetes кеңестері мен амалдары: NGINX және PHP-FPM-де әдемі өшіру мүмкіндіктері

Kubernetes жүйесінде CI/CD енгізудің әдеттегі шарты: қолданба толығымен тоқтатпас бұрын жаңа клиенттік сұрауларды қабылдамауы керек, ең бастысы, барларын сәтті аяқтауы керек.

Kubernetes кеңестері мен амалдары: NGINX және PHP-FPM-де әдемі өшіру мүмкіндіктері

Бұл шартты сақтау орналастыру кезінде нөлдік тоқтап қалуға қол жеткізуге мүмкіндік береді. Дегенмен, өте танымал бумаларды (мысалы, NGINX және PHP-FPM) пайдаланған кезде де, әр орналастыру кезінде қателердің көбеюіне әкелетін қиындықтарға тап болуыңыз мүмкін...

Теория. Қалай өмір сүреді

Біз бұтақтың өмірлік циклі туралы егжей-тегжейлі жариялаған болатынбыз Бұл мақала. Қарастырылып отырған тақырыптың контекстінде бізді мыналар қызықтырады: поддон күйге енген сәтте Аяқтау, оған жаңа сұраулар жіберілмейді (под жойылды қызметке арналған соңғы нүктелер тізімінен). Осылайша, орналастыру кезінде тоқтап қалуды болдырмау үшін қосымшаны тоқтату мәселесін дұрыс шешу жеткілікті.

Сондай-ақ, әдепкі жеңілдік кезеңі екенін есте ұстаған жөн 30 секунд: осыдан кейін подкаст тоқтатылады және қолданбаның осы кезеңге дейін барлық сұрауларды өңдеуге уақыты болуы керек. ескерту: 5-10 секундтан астам уақытты алатын кез келген сұрау қазірдің өзінде проблемалы болса да және әдемі өшіру бұдан былай көмектеспейді...

Қондырғы тоқтаған кезде не болатынын жақсы түсіну үшін келесі диаграмманы қараңыз:

Kubernetes кеңестері мен амалдары: NGINX және PHP-FPM-де әдемі өшіру мүмкіндіктері

A1, B1 - ошақтың күйі туралы өзгерістерді қабылдау
A2 - SIGTERM жөнелту
B2 - соңғы нүктелерден подкастты жою
B3 - өзгертулерді қабылдау (соңғы нүктелер тізімі өзгерді)
B4 - iptables ережелерін жаңарту

Назар аударыңыз: соңғы нүкте қосқышын жою және SIGTERM жіберу дәйекті емес, параллель орындалады. Ingress соңғы нүктелердің жаңартылған тізімін бірден қабылдамайтындықтан, тұтынушылардан жаңа сұраулар подкастқа жіберіледі, бұл подкастты тоқтату кезінде 500 қатені тудырады. (осы мәселе бойынша толығырақ материал үшін біз аударылған). Бұл мәселені келесі жолдармен шешу қажет:

  • Қосылымды жіберу: жауап тақырыптарын жабу (бұл HTTP қолданбасына қатысты болса).
  • Егер кодқа өзгертулер енгізу мүмкін болмаса, келесі мақалада жеңілдік кезеңінің соңына дейін сұрауларды өңдеуге мүмкіндік беретін шешім сипатталған.

Теория. NGINX және PHP-FPM өз процестерін қалай тоқтатады

NGINX

NGINX-тен бастайық, өйткені онымен бәрі азды-көпті анық. Теорияға кірісе отырып, біз NGINX-те бір негізгі процесс және бірнеше «жұмысшылар» бар екенін білеміз - бұл клиент сұрауларын өңдейтін еншілес процестер. Ыңғайлы опция ұсынылады: пәрменді пайдалану nginx -s <SIGNAL> процестерді жылдам өшіру немесе әдемі өшіру режимінде аяқтаңыз. Бізді қызықтыратын соңғы нұсқа екені анық.

Сонда бәрі қарапайым: қосу керек prestop-ілмек әдемі өшіру сигналын жіберетін пәрмен. Мұны контейнер блогында орналастыруда жасауға болады:

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

Енді подвод өшкенде, 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-те қалды", содан кейін подвод тоқтады.

Біз мұндай проблеманы байқай аламыз, мысалы, бізге қажет 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 ешқандай қателерсіз немесе үшінші тарап хабарландыруларынсыз өз процесінің аяқталғанын хабарлайды.

Мәселенің өзі аз немесе көп дәрежеде қолданбаның өзіне байланысты болуы мүмкін және, мысалы, мониторингте көрінбеуі мүмкін екенін түсіндірген жөн. Егер сіз оны кездестірсеңіз, алдымен қарапайым шешім ойға келеді: алдын ала тоқтату ілмегін қосыңыз sleep(30). Ол сізге бұрын болған барлық сұрауларды орындауға мүмкіндік береді (және біз жаңаларын қабылдамаймыз, өйткені pod қазірдің өзінде жағдайда Аяқтау), ал 30 секундтан кейін подводтың өзі сигналмен аяқталады 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 үшін ғана қолданылмайды. Ұқсас жағдай басқа тілдерді/фреймворктарды пайдалану кезінде туындауы мүмкін. Әдемі өшіруді басқа жолдармен түзете алмасаңыз - мысалы, қолданба тоқтату сигналдарын дұрыс өңдейтіндей кодты қайта жазу арқылы - сипатталған әдісті пайдалануға болады. Бұл ең әдемі болмауы мүмкін, бірақ ол жұмыс істейді.

Жаттығу. Қосқыштың жұмысын тексеру үшін сынақты жүктеңіз

Жүктеме сынағы контейнердің қалай жұмыс істейтінін тексеру әдістерінің бірі болып табылады, өйткені бұл процедура пайдаланушылар сайтқа кірген кезде оны нақты ұрыс жағдайларына жақындатады. Жоғарыдағы ұсыныстарды тексеру үшін пайдалануға болады Яндекс.Танк: Ол біздің барлық қажеттіліктерімізді өте жақсы қамтиды. Төменде Grafana және Yandex.Tank графиктерінің арқасында тәжірибемізден нақты мысал келтіре отырып, тестілеуді өткізуге арналған кеңестер мен ұсыныстар берілген.

Бұл жерде ең бастысы өзгерістерді кезең-кезеңімен тексеріңіз. Жаңа түзетуді қосқаннан кейін сынақты іске қосыңыз және нәтижелердің соңғы іске қосумен салыстырғанда өзгергенін тексеріңіз. Әйтпесе, тиімсіз шешімдерді анықтау қиын болады және ұзақ мерзімді перспективада ол тек зиян келтіруі мүмкін (мысалы, орналастыру уақытын ұлғайту).

Тағы бір нюанс - оны тоқтату кезінде контейнер журналдарын қарау. Онда керемет өшіру туралы ақпарат жазылған ба? Басқа ресурстарға (мысалы, көрші PHP-FPM контейнері) кіру кезінде журналдарда қателер бар ма? Қолданбаның өзінде қателер (жоғарыда сипатталған NGINX жағдайындағыдай)? Осы мақаладағы кіріспе ақпарат контейнерді тоқтату кезінде не болатынын жақсы түсінуге көмектеседі деп үміттенемін.

Сонымен, бірінші сынақ жүгірісі онсыз өтті lifecycle және қолданба сервері үшін қосымша директиваларсыз (process_control_timeout PHP-FPM ішінде). Бұл сынақтың мақсаты қателердің шамамен санын (және олардың бар-жоғын) анықтау болды. Сондай-ақ, қосымша ақпараттан сіз әрбір подвод үшін орташа орналастыру уақыты толық дайын болғанша шамамен 5-10 секунд болатынын білуіңіз керек. Нәтижелері:

Kubernetes кеңестері мен амалдары: NGINX және PHP-FPM-де әдемі өшіру мүмкіндіктері

Яндекс.Танк ақпараттық тақтасы орналастыру кезінде орын алған және орташа есеппен 502 секундқа созылған 5 қателіктердің өсуін көрсетеді. Бұл ескі подводқа бар сұраулар тоқтатылған кезде тоқтатылатындықтан болды. Осыдан кейін 503 қате пайда болды, бұл тоқтатылған NGINX контейнерінің нәтижесі болды, ол сонымен қатар серверге байланысты қосылымдарды тоқтатты (бұл Ingress оған қосылуға кедергі болды).

Қалай көрейік process_control_timeout PHP-FPM-де бізге еншілес процестердің аяқталуын күтуге көмектеседі, яғни. мұндай қателерді түзетіңіз. Осы директиваны пайдаланып қайта орналастыру:

Kubernetes кеңестері мен амалдары: NGINX және PHP-FPM-де әдемі өшіру мүмкіндіктері

500-ші орналастыру кезінде қателер болмайды! Орналастыру сәтті болды, өшіру керемет жұмыс істейді.

Дегенмен, уақыт кідірісіне байланысты біз алуы мүмкін қателердің аз пайызы болатын Ingress контейнерлеріне қатысты мәселені есте ұстаған жөн. Оларды болдырмау үшін құрылымды қосу ғана қалады sleep және орналастыруды қайталаңыз. Дегенмен, біздің нақты жағдайда ешқандай өзгерістер көрінбеді (қайтадан қателер жоқ).

қорытынды

Процесті керемет түрде тоқтату үшін қолданбадан келесі әрекетті күтеміз:

  1. Бірнеше секунд күтіп, жаңа қосылымдарды қабылдауды тоқтатыңыз.
  2. Барлық сұраулардың аяқталуын және сұрауларды орындамайтын барлық тірі қосылымдарды жабуды күтіңіз.
  3. Процессіңізді аяқтаңыз.

Дегенмен, барлық қолданбалар осылай жұмыс істей алмайды. Кубернетес шындықтарындағы мәселенің бір шешімі:

  • бірнеше секунд күтетін алдын ала тоқтату ілгегін қосу;
  • сәйкес параметрлер үшін серверіміздің конфигурация файлын зерттеу.

NGINX үлгісі бастапқыда тоқтату сигналдарын дұрыс өңдеуі керек қолданбаның да мұны істемеуі мүмкін екенін анық көрсетеді, сондықтан қолданбаны орналастыру кезінде 500 қатені тексеру өте маңызды. Бұл сондай-ақ мәселені кеңірек қарауға және бір тармаққа немесе контейнерге назар аудармай, бүкіл инфрақұрылымды тұтастай қарауға мүмкіндік береді.

Тестілеу құралы ретінде сіз Yandex.Tank-ті кез келген мониторинг жүйесімен бірге пайдалана аласыз (біздің жағдайда деректер сынақ үшін Prometheus сервері бар Grafana-дан алынды). Әдемі өшіру проблемалары эталон жасай алатын ауыр жүктемелерде анық көрінеді және бақылау сынақ кезінде немесе одан кейін жағдайды егжей-тегжейлі талдауға көмектеседі.

Мақала бойынша кері байланысқа жауап ретінде: мұнда NGINX Ingress-ке қатысты мәселелер мен шешімдер сипатталғанын атап өткен жөн. Басқа жағдайларда басқа шешімдер бар, біз оларды серияның келесі материалдарында қарастырамыз.

PS

K8s кеңестер мен трюктар сериясының басқалары:

Ақпарат көзі: www.habr.com

пікір қалдыру