Архив рубрики: Публикации

Microsoft Edge для Linux: установка и последние новости

Microsoft Edge для Linux: установка и последние новости

Microsoft Edge для Linux: установка и последние новости

Прошло много времени с тех пор, как мы говорили о программное обеспечение с открытым исходным кодом из многих крупные софтверные и интернет-компании с глобальным охватом. Который раньше был известен многим как ГАФАМ+. И поскольку одно из этих программ является новым и текущим Кроссплатформенный браузер МайкрософтСегодня мы решили попробовать.

Итак, сегодня мы познакомимся с Установка «Microsoft Edge для Linux» оценить, как он выглядит и ведет себя, среди прочего.



Читать

Что ждет стоматологию в 2022 году и далее?

Появление COVID-19, за которым последовала быстрая разработка вакцин, привело к тому, что стоматология пережила пару непростых, непредсказуемых лет. Эта турбулентность заставила всех в отрасли задуматься и обеспокоиться тем, что ждет их в 2022 году. Вот наши мысли о том, что ждет стоматологию в следующем году и далее.

 

1. Кадровое обеспечение останется серьезной проблемой после пандемии

Появление COVID-19 привело к огромным изменениям практически во всех аспектах американской жизни, и стоматология не стала исключением. Начиная с полной приостановки оказания неотложной стоматологической помощи на пике вспышки и заканчивая внедрением обновленных методов инфекционного контроля, пандемия оказала серьезное влияние на профессию стоматолога. Можно с уверенностью сказать, что мы продолжим видеть и ощущать изменения в течение всего 2022 года.

В то время как все больше и больше пациентов возвращаются к стоматологу для обычного ухода и других процедур, почти половина стоматологов сообщают, что наем нового персонала после вспышки является фактором № 1, ограничивающим объем. Опрос, проведенный Американской ассоциацией стоматологов, показал, что 35,8% стоматологов-владельцев в настоящее время нанимают ассистентов стоматолога, 28,8% ищут стоматологов-гигиенистов, 26,5% хотят нанять административный персонал и 13,1% ищут младших стоматологов. Более 85% этих стоматологов заявили, что найм на такую должность, как стоматолог-гигиенист, был намного сложнее, чем до пандемии.

Это несоответствие между персоналом и объемом не будет быстро или легко устранено, и мы прогнозируем, что оно станет одной из основных проблем стоматологии в 2022 году.

<

2. Теледентификация продолжит расти

Понятно, что теледентификация набрала обороты во время пандемии. Такие услуги, как виртуальная консультация Delta Dental, обеспечивают простой и безопасный доступ к стоматологической помощи.

Анализ Google trends, опубликованный Journal of Clinical Medicine, выявил пятикратное увеличение числа запросов на “теледентификацию” во время пандемии COVID-19. Любой новый рост несколько ограничен ограничениями teledentistry на сортировку и консультации. Тем не менее, согласно ежегодному исследованию DocASAP о состоянии доступа и вовлеченности пациентов, 40% людей сменили бы поставщика медицинских услуг в зависимости от доступности как телемедицины, так и личных посещений. Теледентинизм переживает момент, и, вероятно, он продлится до 2022 года и далее.

 

3. Новые технологии продолжат изменять отрасль

Стоматология — это область, которая определяется инновациями. Некоторые из технологий, на развитие которых мы будем смотреть в 2022 году и далее, включают:

  • Дополненная реальность. AR нашел пристанище в стоматологии как для образовательных, так и для клинических целей. Но будьте готовы к тому, что в ближайшем будущем это станет все более распространенным в реконструктивных и эстетических процедурах. Приложения AR используют цифровую камеру для наложения виртуальных изображений улучшенного набора зубов перед процедурой. Это позволяет пациентам и стоматологам настраивать такие параметры, как высота и расстояние, по своему вкусу, еще до того, как они войдут в операционную.
  • Виртуальная реальность.VR полностью закрывает внешний мир с помощью специальной гарнитуры и погружает пользователя в виртуальную среду. Надев такую гарнитуру на голову, студенты и начинающие хирурги-стоматологи могут быть доставлены в операционную, или пациенты могут визуализировать успокаивающий пейзаж, сидя в кресле стоматолога, чтобы улучшить свои впечатления.
  • 3D-печать.Поскольку эта технология станет неотъемлемой частью многих медицинских практик, она также все чаще внедряется в зуботехнические лаборатории. Благодаря 3D-принтеру, выполняющему тяжелую работу, зуботехнические лаборатории могут устранить узкое место ручного моделирования и ускорить создание коронок и мостовидных протезов.
  • Чат-боты.По оценкам IBM, чат-бот может ответить до 80% часто задаваемых вопросов клиентов. Неудивительно, что рынок медицинских чат-ботов, как ожидается, достигнет 967,7 миллионов долларов к 2027 году. Чат-боты могут упростить запросы и сэкономить время сотрудников офиса, отвечая на обычные вопросы и даже назначая встречи. По данным IBM, технология может сэкономить предприятиям до 8 миллиардов долларов в 2022 году.
  • Программное обеспечение для подтверждения записи на прием.Как и чат-боты, программное обеспечение для подтверждения приема автоматизирует ранее трудоемкий процесс, подверженный ошибкам и пренебрежению. Многие программные системы подтверждения записи на прием даже предлагают пациентам возможность записываться на прием самостоятельно. В 2022 году ищите программное обеспечение для подтверждения, которое будет продолжать интегрироваться с онлайн-платежами, виртуальной стоматологией и другим офисным программным обеспечением и программным обеспечением для сбора данных.

 

4. Стоматология станет экологичнее

Стоматология — это энерго- и ресурсоемкая отрасль, оказывающая значительное воздействие на окружающую среду. По данным Ассоциации эко-стоматологии, в стоматологических клиниках ежегодно выбрасывается около 680 миллионов ограждений для стульев, легких чехлов для ручек и нагрудников для пациентов, а также 1,7 миллиона мешочков для стерилизации. Многие стоматологи реагируют на опасения по поводу углеродного следа своей практики, и пациенты все чаще выбирают экологически безопасные методы лечения. Отрасль продолжает реагировать на озабоченность поставщиков и пациентов по поводу окружающей среды сновые высокотехнологичные инновации часто позволяют сократить количество отходов. Мы прогнозируем, что в 2022 году и далее все больше стоматологических клиник будут искать способы снизить загрязнение окружающей среды и поддерживать здоровый образ жизни, который выбирают все больше пациентов.



2023-01-04T07:51:49
Здоровье

Неофициальный рабочий стол Google Assistant: как его использовать в GNU/Linux?

Неофициальный рабочий стол Google Assistant: как его использовать в GNU/Linux?

Неофициальный рабочий стол Google Assistant: как его использовать в GNU/Linux?

Использование El программируемые или интеллектуальные персональные помощники в компьютерах всегда было мечтой для многих, используем ли мы Windows, macOS или GNU/Linux или другие менее известные операционные системы. В лучшем случае, самый известный и самый успешный пример на сегодняшний день это было Кортана в Windows, y
Siri на macOS. Однако эти технологии, как правило, гораздо более успешны и популярны на операционные системы мобильных устройствтаких как планшеты, часы, телевизоры и смартфоны.

Именно в этих последних типах устройств выделяются Siri на iOS и Google Ассистент на Android. Поэтому логично попробовать реализовать приложения на компьютерах с Windows, macOS или GNU/Linux. Хорошим примером этого является разработка, известная как: «Неофициальный рабочий стол Google Assistant».



Читать

Проекты искусственного интеллекта 2023: бесплатно, бесплатно и открыто

Проекты искусственного интеллекта 2023: бесплатно, бесплатно и открыто

Проекты искусственного интеллекта 2023: бесплатно, бесплатно и открыто

До и во время 2021 год, когда Бум искусственного интеллекта (ИИ) Это еще не произошло в сфере обычных пользователей, мы уже выложили много технического и информативного контента о текущем состоянии этих технологий и их потенциале.

И с тех пор, В течение 2022 года эта веха, без сомнения, была достигнута.Ну а сегодня мы прокомментируем некоторые известные «Проекты искусственного интеллекта», бесплатно, бесплатно и открыто, стоит знать в 2023 год.



Читать

Kubernetes: Ingress, ошибка 502, readinessProbe и livenessProbe

Имеется приложение на Go, API-бекенд.




Периодически начинает возвращать 502 ошибку, хотя сам под работает и в статусе Running.




Что бы рассмотреть, как и почему Ingress и Service могут возвращать 502, и как работают readinessProbe и livenessProbe в Kubernetes Deployment – напишем простой веб-сервер на Go, в котором опишем два ендпоинта – один будет возвращать нормальный ответ, а во втором – выполнение программы будет прерываться.




Затем задеплоим его в AWS Elastic Kubernetes, создадим Kubernetes Ingress, который создаст AWS Application Load balancer, и потрестируем работу приложения.




Golang HTTP server




Пишем приложение на Go, которое потом упакуем в Docker-контейнер, и запустим в Kubernetes:




package main



import (

    "fmt"

    "log"

    "net/http"

)

  

func main() {

    

    http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request){

        fmt.Fprintf(w, "pong")

    })

      

    http.HandleFunc("/err", func(w http.ResponseWriter, r *http.Request){

        panic("Error")

    })

      

    fmt.Printf("Starting server at port 8080n")

    if err := http.ListenAndServe(":8080", nil); err != nil {

        log.Fatal(err)

    }   

}




Тут мы запускаем http.ListenAndServe() на порту 8080, и определяем два роута:




  • /ping – при обращении сюда всегда возвращаем 200



  • /err – при обращении сюда прерываем выполнение функции с panic, что сэмулировать некорретный ответ приложения




Проверяем локально.




Запускаем:




go run http.go

Starting server at port 8080




Проверяем роут /ping:




curl -I localhost:8080/ping

HTTP/1.1 200 OK




И URI /err, который вызовет panic:




curl -I localhost:8080/err

curl: (52) Empty reply from server




Лог приложения:




go run http.go

Starting server at port 8080

2020/11/11 14:34:53 http: panic serving [::1]:43008: Error

goroutine 6 [running]:

...




Docker образ




Пишем Dockefile:




FROM golang:latest

WORKDIR /app

COPY . .

RUN go build -o main .

EXPOSE 8080

CMD ["./main"]




Собираем образ и пушим в Docker Hub:




docker build -t setevoy/go-http .

docker push setevoy/go-http




Kubernetes




Deployment




Описываем запуск пода с этим образом – создаём 1 под, Service для него, и Ingress, который создаст AWS Application Load Balancer.




Начнём с Deployment:




apiVersion: apps/v1

kind: Deployment

metadata:

  name: go-http

  labels:

    app: go-http

spec:

  replicas: 1

  strategy:

    type: Recreate

  selector: 

    matchLabels:

      app: go-http

  template:

    metadata:

      labels:

        app: go-http

    spec:

      containers:

      - name: go-http

        image: setevoy/go-http

        ports:

        - containerPort: 8080

        imagePullPolicy: Always

        livenessProbe:

          httpGet:

            path: /ping

            port: 8080

          initialDelaySeconds: 1

          periodSeconds: 1

        readinessProbe:

          httpGet:

            path: /ping

            port: 8080

          initialDelaySeconds: 1

          periodSeconds: 1

      restartPolicy: Always




Тут создаём один под, который слушает порт 8080.




В strategy деплоймента указываем Recreate, что бы при тестах не оставались старые поды.




Для него описываем проверки – livenessProbe и readinessProbe, обе проверки ходят на URI /ping, где получают ответ 200.




Позже мы поменяем путь в проверках, и посмотрим, к чему это приведёт.




Service




Создаём Kubernetes Service, который откроет на WorkerNode порт для ALB, и будет роутить трафик к нашему поду на порт 8080 (см. Kubernetes: Service, балансировка нагрузки, kube-proxy и iptables):




---

apiVersion: v1

kind: Service

metadata:

  name: go-http-svc

spec:

  type: NodePort

  ports:

  - port: 80

    targetPort: 8080

    protocol: TCP

  selector:

    app: go-http




Ingress




Добавляем Ingress, который создаст AWS Application Load Balancer, который будет направлять трафик к go-http-svc Service:




--- 

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: go-http-ingress

  annotations:    

    kubernetes.io/ingress.class: alb

    alb.ingress.kubernetes.io/scheme: internet-facing

    alb.ingress.kubernetes.io/healthcheck-path: /ping

    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'

  labels:   

    app: go-http

spec:         

  rules:

  - http: 

      paths:

      - path: /*

        backend: 

          serviceName: go-http-svc

          servicePort: 80




Создаём ресурсы:




kubectl apply -f go-http.yaml

deployment.apps/go-http created

service/go-http-svc created

ingress.extensions/go-http-ingress created




Проверяем под:




kubectl get pod -l app=go-http

NAME                      READY   STATUS    RESTARTS   AGE

go-http-8dc5b4779-7q4kw   1/1     Running   0          8s




И его Ingress:




kubectl get ingress -l app=go-http

NAME              HOSTS   ADDRESS                                                                 PORTS   AGE

go-http-ingress   *       e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com   80      31s




Ждём, пока наш DNS увидит новый URL e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com, и проверяем работу приложения – выполняем запрос к /ping:




curl -I e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/ping

HTTP/1.1 200 OK




Kubernetes Ingress 502




А теперь – обращаемся к ендпоинту /err, который в Go-приложении вызовет panic, и ловим 502 ошибку:




curl -vI e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/err

...

< HTTP/1.1 502 Bad Gateway

HTTP/1.1 502 Bad Gateway

< Server: awselb/2.0

Server: awselb/2.0




Логи пода:




kubectl logs go-http-8dc5b4779-7q4kw

Starting server at port 8080

2020/11/11 12:57:10 http: panic serving 10.3.39.145:8926: Error

goroutine 5169 [running]:

net/http.(*conn).serve.func1(0xc000260e60)

/usr/local/go/src/net/http/server.go:1801 +0x147

panic(0x654840, 0x6f0ba0)

/usr/local/go/src/runtime/panic.go:975 +0x47a

main.main.func2(0x6fa0a0, 0xc00012c540, 0xc000127700)

/app/http.go:16 +0x39

net/http.HandlerFunc.ServeHTTP(0x6bab98, 0x6fa0a0, 0xc00012c540, 0xc000127700)

/usr/local/go/src/net/http/server.go:2042 +0x44

net/http.(*ServeMux).ServeHTTP(0x8615e0, 0x6fa0a0, 0xc00012c540, 0xc000127700)

/usr/local/go/src/net/http/server.go:2417 +0x1ad

net/http.serverHandler.ServeHTTP(0xc0000ea000, 0x6fa0a0, 0xc00012c540, 0xc000127700)

/usr/local/go/src/net/http/server.go:2843 +0xa3

net/http.(*conn).serve(0xc000260e60, 0x6fa4e0, 0xc00011b8c0)

/usr/local/go/src/net/http/server.go:1925 +0x8ad

created by net/http.(*Server).Serve

/usr/local/go/src/net/http/server.go:2969 +0x36c




Тут всё логично – load-balancer отправил наш запрос к поду, под не ответил (вспомним curl: (52) Empty reply from server в наших первых тестах), и мы получили ответ 502 от балансировщика aka Ingress.




readinessProbe и livenessProbe




Теперь посмотрим, как изменение в readinessProbe и livenessProbe повлияют на ответы Ingress и работу самого пода.




readinessProbe




Документация – тут>>>.




readinessProbe используется для проверки того, готов ли под принимать трафик.




Сейчас наш под в статусе Ready:




kubectl get pod -l app=go-http

NAME                      READY   STATUS    RESTARTS   AGE

go-http-8dc5b4779-7q4kw   1/1     Running   0          28m




Или так:




kubectl get pod -l app=go-http -o json | jq '.items[].status.containerStatuses[].ready'

true




И запрос к /ping возвращает нам ответ 200:




curl -I e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/ping

HTTP/1.1 200 OK




Меняем readinessProbe – задаём path=/err, что бы проверка постоянно фейлилась:




...

        readinessProbe:

          httpGet:

            path: /err

...




Передеплоиваем:




kubectl apply -f go-http.yaml

deployment.apps/go-http configured




И проверяем:




kubectl get pod -l app=go-http

NAME                      READY   STATUS    RESTARTS   AGE

go-http-5bd557544-2djcw   0/1     Running   0          4s




Если мы теперь отправим запрос даже на ендпоинт /ping – всё-равно получим 502, т.к. бекенд Сервиса, т.е. под, не принимает трафик, потому что не прошёл readinessProbe:




kubectl get pod -l app=go-http -o json | jq '.items[].status.containerStatuses[].ready'

false




Пробуем:




curl -I e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/ping

HTTP/1.1 502 Bad Gateway




livenessProbe




Документация – тут>>>.




Вернём readinessProbe в /ping, что бы трафик на под пошёл, но изменим livenessProbe – зададим path в /err, а initialDelaySeconds и periodSeconds установим в 15 секунд, плюс добавим failureThreshold равным одной попытке:




...

        livenessProbe:

          httpGet:

            path: /err

            port: 8080

          initialDelaySeconds: 15

          periodSeconds: 15

          failureThreshold: 1

        readinessProbe:

          httpGet:

            path: /ping

...




Теперь после запуска пода Kubernetes выждет 15 секунд, затем выполнит livenessProbe и будет повторять её каждые следующие 15 секунд.




Передеплоиваем, и проверяем:




kubectl get pod -l app=go-http

NAME                       READY   STATUS    RESTARTS   AGE

go-http-78f6c66c8b-q6fkf   1/1     Running   0          6s




Проверяем запрос к ендпоинту /ping:




curl -I e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/ping

HTTP/1.1 200 OK




Всё хорошо.




И /err нам ожидаемо вернёт 502:




curl -I e172ad3e-default-gohttping-ec00-691779486.us-east-2.elb.amazonaws.com/err

HTTP/1.1 502 Bad Gateway




Через 15 секунд, после выполнения первой live проверки – под будет перезапущен:




kubectl get pod -l app=go-http

NAME                       READY   STATUS    RESTARTS   AGE

go-http-668c674dcb-4db9x   0/1     Running   1          19s




Events этого пода:




kubectl describe pod -l app=go-http

...

Normal   Created    6s (x4 over 81s)  kubelet, ip-10-3-55-229.us-east-2.compute.internal  Created container go-http                                                                                                                         

 Warning  Unhealthy  6s (x3 over 66s)  kubelet, ip-10-3-55-229.us-east-2.compute.internal  Liveness probe failed: Get http://10.3.53.103:8080/err: EOF                                                                                       

 Normal   Killing    6s (x3 over 66s)  kubelet, ip-10-3-55-229.us-east-2.compute.internal  Container go-http failed liveness probe, will be restarted                                                                                        

Normal   Started    5s (x4 over 81s)  kubelet, ip-10-3-55-229.us-east-2.compute.internal  Started container go-http




Контейнер в поде не прошёл проверку livenessProbe, и Kubernetes перезапускает под в попытке “починить” его.




Если получится попасть на сам момент перезапуска контейнера – увидим стаус CrashLoopBackOff, а запрос к /ping снова вернёт нам 502:




kubectl get pod -l app=go-http

NAME                       READY   STATUS             RESTARTS   AGE

go-http-668c674dcb-4db9x   0/1     CrashLoopBackOff   4          2m21s




Выводы




Используем readinessProbe для проверки того, что приложение запустилось, в данном случае – Go-бинарник начал прослушивать порт 8080, и на него можно направлять трафик, и используем livenessProbe во время работы пода для проверки того, что приложение в нём все ещё живо.




Если приложение начинает отдавать 502 на определённые запросы – то следует поискать проблему именно в запросах, т.к. если бы была проблема в настройках Ingress/Service – получали бы 502 постоянно.




Самое важное – понимать принципиальную разницу между readinessProbe и livenessProbe:




  • если фейлится readinessProbe – процесс aka контейнер в поде останется в том же состоянии, в котором был на момент сфейленой ready-проверки, но под будет отключен от трафика к нему



  • если фейлится livenessProbe – трафик на под продолжает идти, но контейнер будет перезапущен




Итак, имеем ввиду, что:




  • Если readinessProbe не задана вообще – kubelet будет считать, что под готов к работе, и направит к нему трафик сразу после старта пода. При этом если на  запуск пода уходит минута – то клиенты, которые к нему были направлены после его запуска, будут ждать эту минуту, пока он ответит.



  • Если приложение ловит ошибку, которую не может обработать – оно должно завершить свой процесс, и Kubernetes сам перезапустит контейнер.



  • Используем livenessProbe для проверки состояний, которые нельзя обработать в самом приложении, например – deadlock или бесконечный цикл, при которых контейнер не может ответить на ready-проверку. В таком случае если нет livenessProbe, которая может перезапустить процесс, то под будет отключен от Service – но останется в статусе Running, продолжая потреблять реурсы WorkerNode.




Источник: https://rtfm.co.ua/ru/kubernetes-ingress-oshibka-502-readinessprobe-i-livenessprobe/



2023-01-03T02:03:12
DevOps

Kubernetes: NGINX/PHP-FPM graceful shutdown – избавляемся от 502 ошибок

Имеется PHP-приложение, работает в Kubernetes в подах с двумя контейнерами – NGINX и PHP-FPM.




Проблема: во время скейлинга приложения начинают проскакивать 502 ошибки. Т.е. при остановке подов – некорректно отрабатывает завершение подключений.




Рассмотрим процесс остановки подов вообще, и особенности NGINX и PHP-FPM в частности.




Тестировать будем приложение в AWS Elastic Kubernetes Service с помощью Yandex.Tank.




Ingress создаёт AWS Application Load Balancer с помощью AWS ALB Ingress Controller.




Для управления контейнерами на Kubernetes WorkerNodes испольузется Docker.




Pod Lifecycle – Termination of Pods




Посмотрим, как вообще происходит процесс остановки и удаления подов.




Итак, под – это процесс(ы), запущенные на WorkerNode, для остановки которых используются стандартные сигналы IPC (Inter Process Communication).




Что бы дать возможность поду (процессу/ам) закончить все его текущие операции – система управления контейнерами (container runtime) пытается мягко завершить его работу (graceful shutdown), отправляя сигнал SIGTERM процессу с PID 1 в каждом контейнере этого пода (см. docker stop). При этом, кластер запускает отсчёт grace period перед тем, как жёстко убить под отправкой сигнала SIGKILL.




При этом, можно переопределить сигнал для мягкой остановки используя STOPSIGNAL в образе, из которого запускался контейнер.




Итак, процесс удаления пода выглядит следующим образом:




  1. мы выполняем kubectl delete pod или kubectl scale deployment – запускается процесс удаления подов и стартует таймер отсчёта grace period с дефолтным значением в 30 секунд



  2. API-сервер обновляет статус пода – из Running он становится Terminating (см. Container states). На WorkerNode, на которой этот под запущен, kubelet получает обновление статус этого пода и начинает процесс его остановки:

    1. если для контейнера(ов) в поде есть preStop hook – kubelet  его выполняет. Если хук продолжает выполнение после истечения grace period – добавляется ещё 2 секунды на его завершение. При необходимости можно изменить дефолтные 30 секунд используя terminationGracePeriodSeconds



    2. после завершения preStop хука – kubelet отправляет указание Docker на остановку контейнеров, и Docker отправляет сигнал SIGTERM процессу с PID 1 в каждом контейнере. При этом контейнеры в поде получают сигнал в случайном порядке.




  3. одновременно с началом процесса graceful shutdown – Kubernetes Control Plane (его kube-controller-manager) удаляет останавливаемый под из списка ендпоинтов (см. Kubernetes – Endpoints), и соответствующий Service перестаёт отправлять новые подключения на останавливаемый под



  4. по завершению grace period, kubelet триггерит force shutdown – Docker отправляет сигнал SIGKILL всем оставшимся процесам во всех контейнерах пода, который они проигнорировать не могут, и мгновенно умирают, аварийно завершая все свои операции



  5. kubelet триггерит удаление объекта пода из API-сервера



  6. API-сервер удаляет запись о поде из базы, и под становится недоступен




Наглядная табличка:





Собственно, тут возникает две проблемы:




  1. сам NGINX и PHP-FPM воспринимают SIGTERM как “жестокое убийство”, и завершают работу немедленно, не заботясь о корректном завершении текущих подключений (см. Controlling nginx и php-fpm(8) – Linux man page)



  2. шаги 2 и 3 – отправка SIGTERM и удаление ендпоинта – выполняются одновременно. Однако, обновление данных в Ingress Service происходит не моментально, и под может начать умирать раньше, чем Ingress перестанет на него слать трафик, соотвественно – получим 502, т.к. процесс в поде уже не может принимать подключения




Т.е. в первом случае, если у нас есть подключение к NGINX с keep-alive – то NGINX при выполнении fast shutdown просто обрубит его, а клиент получит 502 ошибку, см. Avoiding dropped connections in nginx containers with “STOPSIGNAL SIGQUIT”.




NGINX STOPSIGNAL и 502




Попробуем воспроизвести проблему с NGINX.




Возмём пример из поста по ссылке выше, и задеплоим его в Кубер.




Пишем Dockerfile:




FROM nginx

RUN echo 'server {n

    listen 80 default_server;n

    location / {n

      proxy_pass      http://httpbin.org/delay/10;n

    }n

}' > /etc/nginx/conf.d/default.conf

CMD ["nginx", "-g", "daemon off;"]




Тут NGINX выполняет proxy_pass на http://httpbin.org, который отвечает с задержкой в 10 секунд – эмулируем работу PHP-бекенда.




Собираем, пушим в репозиторий:




docker build -t setevoy/nginx-sigterm .

docker push setevoy/nginx-sigterm




  • Re-play



  • Copy to Clipboard



  • Pause



  • Full View




Пишем Deployment с 10 подами из собранного образа.




Тут приведу полный файл, с Namespace, Service и Ingress, далее только те части, которые будут меняться:




---

apiVersion: v1

kind: Namespace

metadata:

  name: test-namespace

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: test-deployment

  namespace: test-namespace

  labels:

    app: test

spec:

  replicas: 10

  selector:

    matchLabels:

      app: test

  template:

    metadata:

      labels:

        app: test

    spec:

      containers:

      - name: web

        image: setevoy/nginx-sigterm

        ports:

        - containerPort: 80

        resources:

          requests:

            cpu: 100m

            memory: 100Mi

        readinessProbe:

          tcpSocket:

            port: 80

---

apiVersion: v1

kind: Service

metadata:

  name: test-svc

  namespace: test-namespace

spec:

  type: NodePort

  selector:

    app: test

  ports:

    - protocol: TCP

      port: 80

      targetPort: 80

---

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: test-ingress

  namespace: test-namespace

  annotations:

    kubernetes.io/ingress.class: alb

    alb.ingress.kubernetes.io/scheme: internet-facing

    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'

spec:

  rules:

  - http:

      paths:

      - backend:

          serviceName: test-svc

          servicePort: 80




Деплоим:




kubectl apply -f test-deployment.yaml

namespace/test-namespace created

deployment.apps/test-deployment created

service/test-svc created

ingress.extensions/test-ingress created




Проверяем Ingress:




curl -I aadca942-testnamespace-tes-5874-698012771.us-east-2.elb.amazonaws.com

HTTP/1.1 200 OK




Запущено 10 подов:




kubectl -n test-namespace get pod

NAME                              READY   STATUS    RESTARTS   AGE

test-deployment-ccb7ff8b6-2d6gn   1/1     Running   0          26s

test-deployment-ccb7ff8b6-4scxc   1/1     Running   0          35s

test-deployment-ccb7ff8b6-8b2cj   1/1     Running   0          35s

test-deployment-ccb7ff8b6-bvzgz   1/1     Running   0          35s

test-deployment-ccb7ff8b6-db6jj   1/1     Running   0          35s

test-deployment-ccb7ff8b6-h9zsm   1/1     Running   0          20s

test-deployment-ccb7ff8b6-n5rhz   1/1     Running   0          23s

test-deployment-ccb7ff8b6-smpjd   1/1     Running   0          23s

test-deployment-ccb7ff8b6-x5dc2   1/1     Running   0          35s

test-deployment-ccb7ff8b6-zlqxs   1/1     Running   0          25s




Готовим load.yaml для Yandex.Tank:




phantom:

  address: aadca942-testnamespace-tes-5874-698012771.us-east-2.elb.amazonaws.com

  header_http: "1.1"

  headers:

     - "[Host: aadca942-testnamespace-tes-5874-698012771.us-east-2.elb.amazonaws.com]"

  uris:

    - /    

  load_profile:

    load_type: rps

    schedule: const(100,30m)

  ssl: false

console:

  enabled: true

telegraf:

  enabled: false

  package: yandextank.plugins.Telegraf

  config: monitoring.xml




Тут выполняем 1 запрос в секунду к подам за нашим Ingress (и NGINX в каждом будет ждать 10 секунд ответа от своего “бекенда” перед тем, как ответить 200 нашему Танку).




Запускаем тесты:





Пока всё хорошо.




Теперь скейлим поды с 10 до 1:




kubectl -n test-namespace scale deploy test-deployment --replicas=1

deployment.apps/test-deployment scaled




Поды перешли в Terminating:




kubectl -n test-namespace get pod

NAME                              READY   STATUS        RESTARTS   AGE

test-deployment-647ddf455-67gv8   1/1     Terminating   0          4m15s

test-deployment-647ddf455-6wmcq   1/1     Terminating   0          4m15s

test-deployment-647ddf455-cjvj6   1/1     Terminating   0          4m15s

test-deployment-647ddf455-dh7pc   1/1     Terminating   0          4m15s

test-deployment-647ddf455-dvh7g   1/1     Terminating   0          4m15s

test-deployment-647ddf455-gpwc6   1/1     Terminating   0          4m15s

test-deployment-647ddf455-nbgkn   1/1     Terminating   0          4m15s

test-deployment-647ddf455-tm27p   1/1     Running       0          26m

...




И ловим наши 502 ошибки:





Теперь в Dockerfile добавляем STOPSIGNAL SIGQUIT:




FROM nginx

RUN echo 'server {n

    listen 80 default_server;n

    location / {n

      proxy_pass      http://httpbin.org/delay/10;n

    }n

}' > /etc/nginx/conf.d/default.conf

STOPSIGNAL SIGQUIT

CMD ["nginx", "-g", "daemon off;"]




Билдим, пушим:




docker build -t setevoy/nginx-sigquit .

docker push setevoy/nginx-sigquit




Обновляем деплоймент:




...

    spec:

      containers:

      - name: web

        image: setevoy/nginx-sigquit

        ports:

        - containerPort: 80

...




Передеплоиваем, и проверяем ещё раз.




Запускаем тесты:





Скейлим деплоймент:




kubectl -n test-namespace scale deploy test-deployment --replicas=1

deployment.apps/test-deployment scaled




А ошибок по-прежнему нет:





Прекрасно.




Трафик, preStop и sleep




И всё-таки, если повторить тесты несколько раз, то иногда 502 ошибки всё-таки проскакивают:





Тут мы уже сталкиваемся со второй проблемой – обновление ендпоинтов выполняется параллельно с отправкой SIGTERM.




Добавим preStop хук со sleep, что бы дать время на обновление ендпоинтов – тогда после получения команды на удаление пода, kubelet выждет 5 секунд перед отправкой SIGTERM, за которые Ingress успеет обновить список ендпоинтов:




...

    spec:

      containers:

      - name: web

        image: setevoy/nginx-sigquit

        ports:

        - containerPort: 80

        lifecycle:

          preStop:

            exec:

              command: ["/bin/sleep","5"]

...




Повторяем тесты – всё хорошо.




Выкатили фикс в Production – всё работает замечательно, ошибки пропали, автотесты теперь работают без проблем.




С PHP-FPM проблемы, как оказалось, не было вообще,  т.к. исходный образ изначально был со STOPSIGNAL SIGQUIT.




Другие варианты решения




Конечно, по ходу поиска решения были переброваны самые разные варианты. См. ссылки на интересные материалы в конце, а тут опишу их кратко.




preStop и nginx -s quit




Одним из вариантов было добавить в preStop хук отправку сигнала QUIT в NGINX:




lifecycle:

  preStop:

    exec:

      command:

      - /usr/sbin/nginx

      - -s

      - quit




Но не помогло. Не очень понятно почему, потому как идея вроде бы правильная – вместо того, что бы ожидать TERM от Kubernetes/Docker – мы сами мягко стопаем NGINX, отправляя ему QUIT.




Но можно попробовать.




NGINX + PHP-FPM, supervisord и stopsignal




Наше приложение работает в двух отдельных контейнерах NGINX и PHP-FPM.




Но в процессе поиска решения пробовал использовать образ, в котором оба сервиса собраны в одном образе, например trafex/alpine-nginx-php7.




В нём пробовал добавлять параметр stopsignal и для NGINX, и для PHP-FPM со значением QUIT – но тоже не помогло, хотя идея тоже вроде правильная.




Тем не менее – как вариант на попытку.




PHP-FPM и process_control_timeout




В посте Graceful shutdown in Kubernetes is not always trivial и на Stackoveflow в вопросе Nginx / PHP FPM graceful stop (SIGQUIT): not so graceful есть упоминание о том, что мастер-процесс FPM убивается не дожидаясь своих дочерних процессов, что также может приводить к 502.




Не наш случай, но стоит обратить внимание на параметр process_control_timeout.




NGINX, HTTP и keep-alive session




В принципе, можно было бы указать приложению отправлять заголовок [Connection: close] – тогда клиент по завершении передачи данных закрывал бы соединение, и это уменьшило бы вероятность 502-х. Но они всё равно будут, если NGINX получит SIGTERM в процессе обработки запроса от клиента, а т.к. у нас “сзади” ещё PHP, который ходит в базу – то некоторые запросы могут обрабатываться по 5-10 и более секунд.




См. HTTP persistent connection.




Источник: https://rtfm.co.ua/ru/kubernetes-nginx-php-fpm-graceful-shutdown-izbavlyaemsya-ot-502-oshibok/



2023-01-03T01:50:56
DevOps