Рубрики
Uncategorized

Kubernetes: тестирование нагрузки и нагрузки на грузоподъемность — проблемы и решения

Kubernetes: Тестирование нагрузки и тюнинг с высокой нагрузкой — Проблемы и решения на самом деле, это Po … Теги от AWS, Kubernetes, учебник, DEVOPS.

Kubernetes: тестирование нагрузки и нагрузки на грузоподъемность — проблемы и решения

На самом деле, этот пост был запланирован как короткое описание об использовании Ideaffinity Для Kubernetes Pod:

Но потом, как часто бывает, после начала писать об одном, я столкнулся с другим, а потом еще один, и в результате — я сделал это длительное посмотрение по поводу тестирования нагрузки Kubernetes.

Итак, я начал о Ideaffinity , но потом удивился, как будет Кубернаны кластер-автоскалер Работа — потребуется во внимание настройку Nodefiness во время создания новых рабочих пользователей?

Чтобы проверить это, я сделал простой тест на нагрузку, используя Apache Benchmark Чтобы вызвать Kubernetes HorizontalPodautoScaler которые должны были создать новые стручки, а эти новые стручки должны были вызвать кластер-автоскалер Чтобы создать новые экземпляры AWS EC2, которые будут прикреплены к кластеру Kubernetes в качестве рабочих пользователей.

Затем я начал более сложный тест на нагрузку и сталкиваться с проблемой, когда стручки перестали масштабирование.

А потом … Я решил, что, поскольку я делаю нагрузочные тесты, то может быть хорошая идея проверить различные типы экземпляров AWS EC2 — T3, M5, C5. И, конечно же, нужно добавить результаты к этому посту.

И после этого — мы начали полное тестирование нагрузки и столкнуться с несколькими другими проблемами, и, очевидно, я должен был написать о том, как я их решил.

В конце концов, этот пост о том, что kubernetes Load-Testing в целом, а про типы экземпляров EC2 и о сетевом и DNS и пару других вещей вокруг высокогруженного приложения в кластере Kubernetes.

Примечание : Kk здесь: псевдоним> ~/.bashrc.

Задание

Итак, у нас есть приложение, которое действительно любит ЦП.

Php, laravel. В настоящее время он работает в Digitalocean на 50 беговых капельках, плюс доля NFS, Memcache, Redis и MySQL.

Чего мы хотим, — это переместить это приложение к кластеру Kubernetes в AWS EKS, чтобы сэкономить деньги на инфраструктуре, потому что текущий в DiumperoCean стоит нам около 4000 долларов США/месяц, а один кластер EKS, который стоит около 500-600 долларов США. (сам кластер, плюс на 4 AWS T3.Medium Экземпляры EC2 для рабочих пользователей в двух отделенных людях доступности AWS, полностью 8 EC2).

При этой настройке на Diumpanyocean приложение перестало работать на 12 000 пользователей моделирования (48 000 в час).

Мы хотим продолжать до 15 000 пользователей (60 000/час, 1.440.000/день) на наших AWS EKS с AutoScaling.

Проект будет жить на выделенной группе на рабочих местах, чтобы избежать затрагивания других приложений в кластере. Чтобы создавать новые стручки только на этих рабочих местах — мы будем использовать NodeAffinity.

Кроме того, мы будем выполнять тестирование нагрузки с помощью трех разных типов экземпляров AWS EC2 — T3 , M5 , C5 , выбрать, какой из них лучше подойдет потребности нашей заявки, и сделает еще одно тестирование нагрузки, чтобы проверить, как наш Горизонтальподаутоскалер и кластер-автоскалер буду работать.

Выбор типа EC2

Какой использовать для нас?

Начнем с T3A — немного дешевле, чем общий T3.

EC2 AMD экземпляры

AWS обеспечивает экземпляры процессоров на базе AMD — T3A, M5A, C5A — с почти одинаковым процессором/памятью/сетью, которые они стоят немного меньше, но доступны не в каждом регионе и даже не во всех возможностях одинакового региона.

Например, в регионе AWS US-East-2 C5A доступны в US-East-2B и US-East-2C ДоступностьЗоны — но до сих пор не могут быть использованы в US-East-2a Отказ Поскольку я не хочу менять нашу автоматизацию прямо сейчас (доступностиЗоны выбраны во время предоставления, см. AWS: CloudFation — Использование списков по параметрам ) — тогда мы будем использовать общий тип T3.

ЭК2 Экземпляры гравитона

Кроме того, AWS введен M6G и C6. g Типы экземпляров с AWS Graviton2 процессоры , но использовать их, ваш кластер должен соответствовать некоторым ограничениям, проверять документацию Здесь >>> Отказ

Теперь давайте пойдем вперед и создадим три группы рабочих портов с экземплярами T3, M5 и C5 и проверим потребление ЦП на наше приложение на каждого из них.

Eksctl и Kubernetes Workernode Группы

Файл конфигурации для ваших групп узлов работников выглядит следующим:

---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: "{{ eks\_cluster\_name }}"
  region: "{{ region }}"
  version: "{{ k8s\_version }}"

nodeGroups:

  - name: "eat-test-t3-{{ item }}"
    instanceType: "t3.xlarge"
    privateNetworking: true
    labels: { role: eat-workers }
    volumeSize: 50
    volumeType: gp2
    desiredCapacity: 1
    minSize: 1
    maxSize: 1
    availabilityZones: ["{{ item }}"]
    ssh:
      publicKeyName: "bttrm-eks-nodegroup-{{ region }}"
    iam:
      withAddonPolicies:
        autoScaler: true
        cloudWatch: true
        albIngress: true
        efs: true
    securityGroups:
      withShared: true
      withLocal: true
      attachIDs: [{{ worker\_nodes\_add\_sg }}]

  - name: "eat-test-m5-{{ item }}"
    instanceType: "m5.xlarge"
    privateNetworking: true
    labels: { role: eat-workers }
    volumeSize: 50
    volumeType: gp2
    desiredCapacity: 1
    minSize: 1
    maxSize: 1
    availabilityZones: ["{{ item }}"]
    ssh:
      publicKeyName: "bttrm-eks-nodegroup-{{ region }}"
    iam:
      withAddonPolicies:
        autoScaler: true
        cloudWatch: true
        albIngress: true
        efs: true
    securityGroups:
      withShared: true
      withLocal: true
      attachIDs: [{{ worker\_nodes\_add\_sg }}]

  - name: "eat-test-c5-{{ item }}"
    instanceType: "c5.xlarge"
    privateNetworking: true
    labels: { role: eat-workers }
    volumeSize: 50
    volumeType: gp2
    desiredCapacity: 1
    minSize: 1
    maxSize: 1
    availabilityZones: ["{{ item }}"]
    ssh:
      publicKeyName: "bttrm-eks-nodegroup-{{ region }}"
    iam:
      withAddonPolicies:
        autoScaler: true
        cloudWatch: true
        albIngress: true
        efs: true
    securityGroups:
      withShared: true
      withLocal: true
      attachIDs: [{{ worker\_nodes\_add\_sg }}]

Здесь у нас есть три группы узел рабочие, каждый с собственным типом EC2.

Развертывание описано с использованием Anisible и Экктл см. AWS Elastic Kubernetes Service: автоматизация создания кластера, часть 2 — Anisible, eksctl пост, в двух разных доступных случаях.

Minsize и Maxsize установлены на 1 Таким образом, наш кластер AutoScaLer не начнет их масштабировать — у прошу прошумирования тестов я хочу увидеть нагрузку CPU на единственном экземпляре EC2 и для запуска kubectl Top для стручек и узлов.

После того, как мы выберем наиболее подходящего типа EC2 для нас — бросит другие группы рабочихерных и включите автоскализацию.

План тестирования

Что и как мы проверим:

  • PHP, Laravel, упакованный в докерный образ
  • Все серверы имеют 4 ядра CPU и 16 ГБ ОЗУ (исключая RAM C5-8 GB)
  • В развертывании приложения с Запросы Мы установим, чтобы запустить только один POD на рабочую сторону, попросив немного больше их половину на его процессоре, так что планировщик Kubernetes должен будет разместить POD на выделенный экземпляр рабочего режима
  • Используя Ideaffinity Мы поставим на наших стручках только на необходимых рабочих местах
  • Стручки и кластерные автоскализаторы отключены сейчас

Мы создадим три группы рабочих портов с разными типами EC2 и развернут приложение на четыре пространства имен Kubernetes — один «по умолчанию» и три на каждый тип экземпляра.

В каждом таком пространстве имен приложение внутри будет настроено с помощью Ideaffinity Для бега на необходимый тип EC2.

Делая это, у нас будет четыре Вход Ресурсы с AWS LoadBalancer, Смотрите Kubernetes: Clusterip VS NodePort VS LoadBalancer, Services и Ingress — обзор с примерами И у нас будет четыре конечных точка для испытаний.

Kubernetes NodeAffinity && Nodeselector

Документация — Назначение стручков к узлам Отказ

Чтобы выбрать, на каком уземе работника Kubernetes должен запустить POD, мы можем использовать две типы меток — созданные самими собой или назначенными рабочими узлами Kubernetes.

В нашем файле конфигурации для рабочих пользователей мы установили такую метку:

...
labels: { role: eat-workers }
...

Который будет прикреплен к каждому EC2, созданному в этой группе рабочего режима.

Обновите кластер:

И давайте проверим все теги на экземпляр:

Давайте проверим группы для рабочих портов с Экктл :

$ eksctl — profile arseniy — cluster bttrm-eks-dev-1 get nodegroups
CLUSTER NODEGROUP CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID
bttrm-eks-dev-1 eat-test-c5-us-east-2a 2020–08–20T09:29:28Z 1 1 1 c5.xlarge ami-0f056ad53eddfda19
bttrm-eks-dev-1 eat-test-c5-us-east-2b 2020–08–20T09:34:54Z 1 1 1 c5.xlarge ami-0f056ad53eddfda19
bttrm-eks-dev-1 eat-test-m5-us-east-2a 2020–08–20T09:29:28Z 1 1 1 m5.xlarge ami-0f056ad53eddfda19
bttrm-eks-dev-1 eat-test-m5-us-east-2b 2020–08–20T09:34:54Z 1 1 1 m5.xlarge ami-0f056ad53eddfda19
bttrm-eks-dev-1 eat-test-t3-us-east-2a 2020–08–20T09:29:27Z 1 1 1 t3.xlarge ami-0f056ad53eddfda19
bttrm-eks-dev-1 eat-test-t3-us-east-2b 2020–08–20T09:34:54Z 1 1 1 t3.xlarge ami-0f056ad53eddfda19

Давайте проверим созданный экземпляр Workernode ES2 с помощью The -L, чтобы выбрать только те, которые имеют нашу собственную этикетку « Роль: есть рабочие » и сортируя их по их типам EC2:

$ kk -n eks-dev-1-eat-backend-ns get node -l role=eat-workers -o=json | jq -r '[.items | sort\_by(.metadata.labels["beta.kubernetes.io/instance-type"])[] | {name:.metadata.name, type:.metadata.labels["beta.kubernetes.io/instance-type"], region:.metadata.labels["failure-domain.beta.kubernetes.io/zone"]}]'
[
{
"name": "ip-10–3–47–253.us-east-2.compute.internal",
"type": "c5.xlarge",
"region": "us-east-2a"
},
{
"name": "ip-10–3–53–83.us-east-2.compute.internal",
"type": "c5.xlarge",
"region": "us-east-2b"
},
{
"name": "ip-10–3–33–222.us-east-2.compute.internal",
"type": "m5.xlarge",
"region": "us-east-2a"
},
{
"name": "ip-10–3–61–225.us-east-2.compute.internal",
"type": "m5.xlarge",
"region": "us-east-2b"
},
{
"name": "ip-10–3–45–186.us-east-2.compute.internal",
"type": "t3.xlarge",
"region": "us-east-2a"
},
{
"name": "ip-10–3–63–119.us-east-2.compute.internal",
"type": "t3.xlarge",
"region": "us-east-2b"
}
]

Узнать больше о форматировании kubectl выхода Здесь >> >

Обновление развертывания

Nodeselector Пользовательская этикетка

Сначала давайте разверним наше приложение для всех экземпляров с Этикетки: {роль: есть работники} — Kubernetes придется создать стручки на 6 серверов — на двоих на каждом типе EC2.

Обновите развертывание, добавьте Nodeselector с роль Этикетка с ценностью « есть рабочие »:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}
  annotations:
    reloader.stakater.com/auto: "true"
spec:
  replicas: {{ .Values.replicaCount }}
  strategy:
    type: RollingUpdate
  selector:
    matchLabels:
      application: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        application: {{ .Chart.Name }}
        version: {{ .Chart.Version }}-{{ .Chart.AppVersion }}
        managed-by: {{ .Release.Service }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: {{ .Values.image.registry }}/{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag }}
        imagePullPolicy: Always
...
        ports:
          - containerPort: {{ .Values.appConfig.port }}
        livenessProbe:
          httpGet:
            path: {{ .Values.appConfig.healthcheckPath }}
            port: {{ .Values.appConfig.port }}
          initialDelaySeconds: 10
        readinessProbe:
          httpGet:
            path: {{ .Values.appConfig.healthcheckPath }}
            port: {{ .Values.appConfig.port }}
          initialDelaySeconds: 10
        resources:
          requests:
            cpu: {{ .Values.resources.requests.cpu | quote }}
            memory: {{ .Values.resources.requests.memory | quote }}
      nodeSelector:
        role: eat-workers
      volumes:
      imagePullSecrets:
        - name: gitlab-secret

репликонт Установлено на 6, согласно номеру экземпляров.

Развернуть это:

$ helm secrets upgrade --install --namespace eks-dev-1-eat-backend-ns --set image.tag=179217391 --set appConfig.appEnv=local --set appConfig.appUrl=https://dev-eks.eat.example.com/ --atomic eat-backend . -f secrets.dev.yaml --debug

Проверить:

$ kk -n eks-dev-1-eat-backend-ns get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector

NAME STATUS NODE TYPE
eat-backend-57b7b54d98–7m27q Running ip-10–3–63–119.us-east-2.compute.internal map[role:eat-workers]
eat-backend-57b7b54d98–7tvtk Running ip-10–3–53–83.us-east-2.compute.internal map[role:eat-workers]
eat-backend-57b7b54d98–8kphq Running ip-10–3–47–253.us-east-2.compute.internal map[role:eat-workers]
eat-backend-57b7b54d98-l24wr Running ip-10–3–61–225.us-east-2.compute.internal map[role:eat-workers]
eat-backend-57b7b54d98-ns4nr Running ip-10–3–45–186.us-east-2.compute.internal map[role:eat-workers]
eat-backend-57b7b54d98-sxzk4 Running ip-10–3–33–222.us-east-2.compute.internal map[role:eat-workers]
eat-backend-memcached-0 Running ip-10–3–63–119.us-east-2.compute.internal 

Хорошо — у нас есть наши 6 стручков на 6 рабочих местах.

Nodeselector от Kuber Label

Теперь давайте обновим развертывание, чтобы использовать этикетки, установленные самими kubernetes, например, мы можем использовать beta.kubernetes.io/instance-type Где мы можем установить тип экземпляра, который мы хотели бы использовать для развертывания POD только на EC2 выбранного типа.

репликонт Теперь установлено значение 2 в соответствии с примером того же типа — будет иметь два стручка, работающих на двух EC2.

Снимите развертывание:

$ helm --namespace eks-dev-1-eat-backend-ns uninstall eat-backend
release "eat-backend" uninstalled

Обновите манифест — добавьте T3 Так что оба условия будут работать — роль и Тип экземпляра :

...
      nodeSelector:
        beta.kubernetes.io/instance-type: t3.xlarge
        role: eat-workers
...

Давайте разверним их до трех новых пространств имен, и давайте добавим постфикс к каждому из T3, M5, C5, поэтому для группы T3 имя будет « EKS-DEV-1-EAT — BASHEND-NS- T3 «.

Добавьте --create-пространство имен Для хелмы:

$ helm secrets upgrade --install --namespace eks-dev-1-eat-backend-ns-t3 --set image.tag=180029557 --set appConfig.appEnv=local --set appConfig.appUrl=https://t3-dev-eks.eat.example.com/ --atomic eat-backend . -f secrets.dev.yaml --debug --create-namespace

Повторите то же самое для M5, C5 и проверьте.

T3:

$ kk -n eks-dev-1-eat-backend-ns-t3 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector
NAME STATUS NODE TYPE
eat-backend-cc9b8cdbf-tv9h5 Running ip-10–3–45–186.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:t3.xlarge role:eat-workers]
eat-backend-cc9b8cdbf-w7w5w Running ip-10–3–63–119.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:t3.xlarge role:eat-workers]
eat-backend-memcached-0 Running ip-10–3–53–83.us-east-2.compute.internal 

M5:

$ kk -n eks-dev-1-eat-backend-ns-m5 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector
NAME STATUS NODE TYPE
eat-backend-7dfb56b75c-k8gt6 Running ip-10–3–61–225.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:m5.xlarge role:eat-workers]
eat-backend-7dfb56b75c-wq9n2 Running ip-10–3–33–222.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:m5.xlarge role:eat-workers]
eat-backend-memcached-0 Running ip-10–3–47–253.us-east-2.compute.internal 

И C5:

$ kk -n eks-dev-1-eat-backend-ns-c5 get pod -o=custom-columns=NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName,TYPE:.spec.nodeSelector
NAME STATUS NODE TYPE
eat-backend-7b6778c5c-9g6st Running ip-10–3–47–253.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:c5.xlarge role:eat-workers]
eat-backend-7b6778c5c-sh5sn Running ip-10–3–53–83.us-east-2.compute.internal map[beta.kubernetes.io/instance-type:c5.xlarge role:eat-workers]
eat-backend-memcached-0 Running ip-10–3–47–58.us-east-2.compute.internal 

Все готово к тестированию.

Тестирование AWS EC2 T3 VS M5 VS C5

Запустите тесты, один и тот же набор для всех групп рабочихернгов, и посмотреть на расход CPU с помощью стручков.

T3.

Стручки:

$ kk top nod-n eks-dev-1-eat-backend-ns-t3 top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-79cfc4f9dd-q22rh 1503m 103Mi
eat-backend-79cfc4f9dd-wv5xv 1062m 106Mi
eat-backend-memcached-0 1m 2Mi

Узлы:

$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=t3.xlarge
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–45–186.us-east-2.compute.internal 1034m 26% 1125Mi 8%
ip-10–3–63–119.us-east-2.compute.internal 1616m 41% 1080Mi 8%

M5.

Стручки:

$ kk -n eks-dev-1-eat-backend-ns-m5 top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-6f5d68778d-484lk 1039m 114Mi
eat-backend-6f5d68778d-lddbw 1207m 105Mi
eat-backend-memcached-0 1m 2Mi

Узлы:

$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=m5.xlarge
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–33–222.us-east-2.compute.internal 1550m 39% 1119Mi 8%
ip-10–3–61–225.us-east-2.compute.internal 891m 22% 1087Mi 8%

C5.

Стручки:

$ kk -n eks-dev-1-eat-backend-ns-c5 top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-79b947c74d-mkgm9 941m 103Mi
eat-backend-79b947c74d-x5qjd 905m 107Mi
eat-backend-memcached-0 1m 2Mi

Узлы:

$ kk top node -l role=eat-workers,beta.kubernetes.io/instance-type=c5.xlarge
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–47–253.us-east-2.compute.internal 704m 17% 1114Mi 19%
ip-10–3–53–83.us-east-2.compute.internal 1702m 43% 1122Mi 19%

На самом деле, вот и все.

Результаты:

  • T3 : 1000-1500 мкпу, 385 мс ответ
  • M5 : 1000-1200 мкпу, 371 мс ответ
  • C5 : 900-1000 МКПУ, 370 мс ответ

Итак, давайте используем тип S5 сейчас, поскольку они, кажется, лучше, используя процессор.

Kubernetes Nodeaffinity VS Kubernetes CluerautoScaler

Одним из главных вопросов, с которыми я борется — будет ли автоскалер кластера уважать Ideaffinity ?

Идти вперед — да, это будет.

Наше Горизонтальподаутоскалер выглядит так:

---         
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ .Chart.Name }}-hpa
spec:       
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ .Chart.Name }}
  minReplicas: {{ .Values.hpa.minReplicas }}
  maxReplicas: {{ .Values.hpa.maxReplicas }}
  metrics:    
  - type: Resource
    resource:
      name: cpu
      target: 
        type: Utilization
        averageUtilization: {{ .Values.hpa.cpuUtilLimit }}

cpuutillimit Установлено на 30%, поэтому, когда PHP-FPM начнет активно использовать свои FPM-работники — тогда нагрузка на процессор повысится, и предел 30% даст нам некоторое время для раскрутки новых экземпляров EC2, пока уже существующие средства будут сохранять уже существующие соединения.

Смотрите Kubernetes: HorizontalPodautoScaler — обзор с примерами пост для более подробной информации.

Nodeselector Теперь описывается с помощью шаблона HELM и его Значения.yaml Проверьте Helm: Cubernetes Package Manager — обзор, начать :

...
      nodeSelector:
        beta.kubernetes.io/instance-type: {{ .Values.nodeSelector.instanceType | quote }}
        role: {{ .Values.nodeSelector.role | quote }}
...

И его ценности.yaml:

...
nodeSelector: 
  instanceType: "c5.xlarge"
  role: "eat-workers
...

Восстановите все, и давайте начнем с полного тестирования нагрузки.

Без действия во всех ресурсах расход было следующим:

$ kk -n eks-dev-1-eat-backend-ns top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-b8b79574–8kjl4 50m 55Mi
eat-backend-b8b79574–8t2pw 39m 55Mi
eat-backend-b8b79574-bq8nw 52m 68Mi
eat-backend-b8b79574-swbvq 40m 55Mi
eat-backend-memcached-0 2m 6Mi

На 4-х … C5.xlarge Сервер (4 ядра, 8 ГБ ОЗУ):

$ kk top node -l role=eat-workers
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–34–151.us-east-2.compute.internal 105m 2% 1033Mi 18%
ip-10–3–39–132.us-east-2.compute.internal 110m 2% 1081Mi 19%
ip-10–3–54–32.us-east-2.compute.internal 166m 4% 1002Mi 17%
ip-10–3–56–98.us-east-2.compute.internal 106m 2% 1010Mi 17%

И уже упомянул Горизонтальподаутоскалер С 30% CPU Запросы Ограничение:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 1%/30% 4 40 4 6m27s

Тестирование нагрузки

1 день

Короче говоря, это был самый первый день всего тестирования, который всего три дня занял три дня.

Этот тест был выполнен в четырех T3A.Medium Экземпляры с той же 1 POD на рабочемоне с включенным HPA и кластерным автоскалером.

И все прошло хорошо, пока мы не добрались до 8000 одновременных пользователей — см. Время ответа:

И стручки перестали на масштабирование:

Потому что они перестали создавать более 30% загрузки процессора.

Самое первое мое предположение было правильным: PHP-FPM был настроен как OnDemand С максимум 5 рабочих FPM (см. PHP-FPM: Manager Process Manager — Dynamic vs ondemand vs статически , Рус ).

Итак, FPM начал 5 работников, которые не могут сделать больше нагрузки на ядра ЦП более 30% от запросов от Развертывание И HPA перестал их масштабировать.

На второй день мы изменили его на Динамический (И на третьем — к статично Во избежание проведения времени для создания новых процессов) с максимальными 50 работниками — после этого они начали генерировать загрузку ЦП все время, поэтому HPA продолжал масштабировать наши стручки.

Хотя есть еще одно решение, как просто, чтобы добавить еще одно условие для HPA, например — LoadsAlancer Connections, а затем мы сделаем это (см. Kubernetes: мониторинг кластера с оператором PROMETHEUS ).

День 2

Исходя из испытаний JMeter, используя те же тесты, как вчера (а завтра).

Начните с одного пользователя и увеличить их до 15.000 одновременных пользователей.

Нынешняя инфраструктура на цифровой камере обрабатывается 12 000 на максимуме — но на AWS EKS мы хотим, чтобы иметь возможность не допустить до 15 000 пользователей.

Поехали:

На 3300 пользователей Pods начал масштабирование:

…
0s Normal SuccessfulRescale HorizontalPodAutoscaler New size: 5; reason: cpu resource utilization (percentage of request) above target
0s Normal ScalingReplicaSet Deployment Scaled up replica set eat-backend-b8b79574 to 5
0s Normal SuccessfulCreate ReplicaSet Created pod: eat-backend-b8b79574-l68vq
0s Warning FailedScheduling Pod 0/12 nodes are available: 12 Insufficient cpu, 8 node(s) didn't match node selector.
0s Warning FailedScheduling Pod 0/12 nodes are available: 12 Insufficient cpu, 8 node(s) didn't match node selector.
0s Normal TriggeredScaleUp Pod pod triggered scale-up: [{eksctl-bttrm-eks-dev-1-nodegroup-eat-us-east-2b-NodeGroup-1N0QUROWQ8K2Q 2->3 (max: 20)}]
…

И новые узлы EC2, а также:

$ kk -n eks-dev-1-eat-backend-ns top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-b8b79574–8kjl4 968m 85Mi
eat-backend-b8b79574–8t2pw 1386m 85Mi
eat-backend-b8b79574-bq8nw 737m 71Mi
eat-backend-b8b79574-l68vq 0m 0Mi
eat-backend-b8b79574-swbvq 573m 71Mi
eat-backend-memcached-0 20m 15Mi

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 36%/30% 4 40 5 37m

$ kk top node -l role=eat-workers
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–34–151.us-east-2.compute.internal 662m 16% 1051Mi 18%
ip-10–3–39–132.us-east-2.compute.internal 811m 20% 1095Mi 19%
ip-10–3–53–136.us-east-2.compute.internal 2023m 51% 567Mi 9%
ip-10–3–54–32.us-east-2.compute.internal 1115m 28% 1032Mi 18%
ip-10–3–56–98.us-east-2.compute.internal 1485m 37% 1040Mi 18%

5500 — все хорошо до сих пор:

NET/HTTP: запрос отменен (клиент. Тайм-аут превышен во время ожидания заголовков)

На 7 000-8.000 мы столкнулись с проблемами — PODS начала неспособность к тому, что ЛИЦИВНОЕ ИСКЛЮЧЕНИЕ И ЛИЧНОСТЬ И ЛЮБИМОСТИ ДЛЯ ЛИЧНОСТИ КЛИЕНТАМИ. Тайм-аут превышен во время ожидания заголовков » ошибка:

0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.38.7:80/:](http://10.3.38.7:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)
1s Warning Unhealthy Pod Readiness probe failed: Get [http://10.3.44.96:80/:](http://10.3.44.96:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)
0s Normal MODIFY Ingress rule 1 modified with conditions [{ Field: "path-pattern", Values: ["/\*"] }]
0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.44.34:80/:](http://10.3.44.34:80/:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)

И с большим количеством пользователей это только хуже — 10.000:

Стручки начали терпеть неудачу почти все время, и худшее было то, что у нас даже не было никаких журналов из приложения — он продолжил писать в журнал файла внутри контейнеров, и мы исправили это только на третий день.

Нагрузка была такой:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 60%/30% 4 40 15 63m

$ kk top node -l role=eat-workers
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–33–155.us-east-2.compute.internal 88m 2% 951Mi 16%
ip-10–3–34–151.us-east-2.compute.internal 1642m 41% 1196Mi 20%
ip-10–3–39–128.us-east-2.compute.internal 67m 1% 946Mi 16%
ip-10–3–39–132.us-east-2.compute.internal 73m 1% 1029Mi 18%
ip-10–3–43–76.us-east-2.compute.internal 185m 4% 1008Mi 17%
ip-10–3–47–243.us-east-2.compute.internal 71m 1% 959Mi 16%
ip-10–3–47–61.us-east-2.compute.internal 69m 1% 945Mi 16%
ip-10–3–53–124.us-east-2.compute.internal 61m 1% 955Mi 16%
ip-10–3–53–136.us-east-2.compute.internal 75m 1% 946Mi 16%
ip-10–3–53–143.us-east-2.compute.internal 1262m 32% 1110Mi 19%
ip-10–3–54–32.us-east-2.compute.internal 117m 2% 985Mi 17%
ip-10–3–55–140.us-east-2.compute.internal 992m 25% 931Mi 16%
ip-10–3–55–208.us-east-2.compute.internal 76m 1% 942Mi 16%
ip-10–3–56–98.us-east-2.compute.internal 1578m 40% 1152Mi 20%
ip-10–3–59–239.us-east-2.compute.internal 1661m 42% 1175Mi 20%

$ kk -n eks-dev-1-eat-backend-ns top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-b8b79574–5d6zl 0m 0Mi
eat-backend-b8b79574–7n7pq 986m 184Mi
eat-backend-b8b79574–8t2pw 709m 135Mi
eat — backend-b8b79574-bq8nw 0m 0Mi
eat-backend-b8b79574-ds68n 0m 0Mi
eat-backend-b8b79574-f4qcm 0m 0Mi
eat-backend-b8b79574-f6wfj 0m 0Mi
eat-backend-b8b79574-g7jm7 842m 165Mi
eat-backend-b8b79574-ggrdg 0m 0Mi
eat-backend-b8b79574-hjcnh 0m 0Mi
eat-backend-b8b79574-l68vq 0m 0Mi
eat-backend-b8b79574-mlpqs 0m 0Mi
eat-backend-b8b79574-nkwjc 2882m 103Mi
eat-backend-b8b79574-swbvq 2091m 180Mi
eat-backend-memcached-0 31m 54Mi

А стручки перезапущен бесконечно:

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-b8b79574–5d6zl 0/1 CrashLoopBackOff 6 17m
eat-backend-b8b79574–7n7pq 1/1 Running 5 9m13s
eat-backend-b8b79574–8kjl4 0/1 CrashLoopBackOff 7 64m
eat-backend-b8b79574–8t2pw 0/1 CrashLoopBackOff 6 64m
eat-backend-b8b79574-bq8nw 1/1 Running 6 64m
eat-backend-b8b79574-ds68n 0/1 CrashLoopBackOff 7 17m
eat-backend-b8b79574-f4qcm 1/1 Running 6 9m13s
eat-backend-b8b79574-f6wfj 0/1 Running 6 9m13s
eat-backend-b8b79574-g7jm7 0/1 CrashLoopBackOff 5 25m
eat-backend-b8b79574-ggrdg 1/1 Running 6 9m13s
eat-backend-b8b79574-hjcnh 0/1 CrashLoopBackOff 6 25m
eat-backend-b8b79574-l68vq 1/1 Running 7 29m
eat-backend-b8b79574-mlpqs 0/1 CrashLoopBackOff 6 21m
eat-backend-b8b79574-nkwjc 0/1 CrashLoopBackOff 5 9m13s
eat-backend-b8b79574-swbvq 0/1 CrashLoopBackOff 6 64m
eat-backend-memcached-0 1/1 Running 0 64m

После 12.000-13.000 пользователей у нас было только один POD alive:

$ kk -n eks-dev-1-eat-backend-ns top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-b8b79574–7n7pq 0m 0Mi
eat-backend-b8b79574–8kjl4 0m 0Mi
eat-backend-b8b79574–8t2pw 0m 0Mi
eat — backend-b8b79574-bq8nw 0m 0Mi
eat-backend-b8b79574-ds68n 0m 0Mi
eat-backend-b8b79574-f4qcm 0m 0Mi
eat-backend-b8b79574-f6wfj 0m 0Mi
eat-backend-b8b79574-g7jm7 0m 0Mi
eat-backend-b8b79574-ggrdg 0m 0Mi
eat-backend-b8b79574-hjcnh 0m 0Mi
eat-backend-b8b79574-l68vq 0m 0Mi
eat-backend-b8b79574-mlpqs 0m 0Mi
eat-backend-b8b79574-nkwjc 3269m 129Mi
eat-backend-b8b79574-swbvq 0m 0Mi
eat-backend-memcached-0 23m 61Mi

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-b8b79574–5d6zl 1/1 Running 7 20m
eat-backend-b8b79574–7n7pq 0/1 CrashLoopBackOff 6 12m
eat-backend-b8b79574–8kjl4 0/1 CrashLoopBackOff 7 67m
eat-backend-b8b79574–8t2pw 0/1 CrashLoopBackOff 7 67m
eat-backend-b8b79574-bq8nw 0/1 CrashLoopBackOff 6 67m
eat-backend-b8b79574-ds68n 0/1 CrashLoopBackOff 8 20m
eat-backend-b8b79574-f4qcm 0/1 CrashLoopBackOff 6 12m
eat-backend-b8b79574-f6wfj 0/1 CrashLoopBackOff 6 12m
eat-backend-b8b79574-g7jm7 0/1 CrashLoopBackOff 6 28m
eat-backend-b8b79574-ggrdg 0/1 Running 7 12m
eat-backend-b8b79574-hjcnh 0/1 CrashLoopBackOff 7 28m
eat-backend-b8b79574-l68vq 0/1 CrashLoopBackOff 7 32m
eat-backend-b8b79574-mlpqs 0/1 CrashLoopBackOff 7 24m
eat-backend-b8b79574-nkwjc 1/1 Running 7 12m
eat-backend-b8b79574-swbvq 0/1 CrashLoopBackOff 7 67m
eat-backend-memcached-0 1/1 Running 0 67m

И только в этот момент я вспомнил о логических файлах в контейнерах и проверил их — я нашел, что наш сервер базы данных начал отказываться от подключения:

bash-4.4# cat ./new-eat-backend/storage/logs/laravel-2020–08–20.log
[2020–08–20 16:53:25] production.ERROR: SQLSTATE[HY000] [2002] Connection refused {"exception":"[object] (Doctrine\\DBAL\\Driver\\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:27)

AWS RDS — «Соединение отказано»

Для баз данных мы используем RDS Aurora Mysql со своими собственными автоскализациями.

Выпуск вот в том, что сначала тестирование выполняется в среде Dev, которая имеет небольшие экземпляры базы данных — db.t2.medium С 4 ГБ ОЗУ, а через секунду — все запросы от приложения были отправлены на главный экземпляр БД, пока рабы Aurora не использовались вообще. Мастер послужил около 155 запросов в секунду.

На самом деле, одним из основных преимуществ RDS Aurora является именно главным/подчиненным разделением — все запросы на изменение данных ( обновление , Создать и т. Д.) ДОЛЖЕН быть отправлен в мастер, пока все Выберите — до раба.

Во время этого рабы могут быть масштабированы своими собственными аутокалинговыми политиками:

Кстати, мы делаем это не в том порядке — лучше нас масштабировать рабов по номеру подключений, а не CPU. Изменит это позже.

AWS RDS Max Connections

На самом деле, согласно Документация — Для пределов подключений для T3.Medium должны быть 90 соединений одновременно, пока мы были отклонены после 50-60:

Я говорил с AWS Arductures, а затем спросил их о «90 соединений в документации» — но они не могли помочь нам с ответом, как « Может быть, это до _ 90_? «

И вообще, после испытаний у нас была такая картина:

52% потерпели неудачу, и это, очевидно, действительно плохо:

Но для меня главное здесь было то, что сам кластер, его самолет, и сеть работала, как ожидалось.

Проблема базы данных будет решена на третий день — обновит тип экземпляра и настроит приложение для начала работы с рабами Aurora.

3 день

Ну — самый интересный день:-)

Сначала — разработчики фиксированные Aurora Plaves, поэтому приложение будет использовать их сейчас.

Кстати, говорил с командой AWS вчера, и они рассказали мне о RDS прокси Сервис — нужно проверить это, выглядит многообещающим.

Также необходимо проверить настройку OPCAChe, поскольку он может уменьшить использование ЦП, см. PHP: Кеширование PHP-скриптов — Настройка и Тюнинг Опкаш (в рус).

В то время как разработчики делают свои изменения — давайте посмотрим на наших чувствительностях и готовности Kubernetes и готовности.

Kubernetes Livys и готовности

Нашел пару интересных постов — Kubernetes Lives и готовности зондов: как избежать стрельбы себя в ноге и Живит и готовность зондов с Laravel Отказ

Наши разработчики уже добавлены два новых конечных точка:

...
$router->get('healthz', 'HealthController@phpCheck');
$router->get('readiness', 'HealthController@dbReadCheck');
...

И HealthController следующий:

ok == 1) {
                return response('ok');
            }
        } catch (\Throwable $err) {
            // ignore
        }
        return response('err', 500);
    }
}

По /Healthz URI Мы проверим, что сам Pod запущен, а PHP работает.

По /Готовность — Убедитесь, что приложение запущено и готово принять соединения:

  • ЛИЦИВНОЕ ПРОБРАЖА : Если не удалось — kubernetes перезапустит стручок
  • INationalDelayseconds : должно быть длиннее максимального времени инициализации для контейнера — Сколько Larave нужно? Давайте установим его до 5 секунд
  • FailureTheReshold : три попытки, если они все будут потерпеть неудачу — POD будет перезапущен
  • Периоды : значение по умолчанию составляет 15 секунд, как я помню — пусть это будет так
  • readishprobe : Определяет, когда приложение готово к обслуживанию запросов. Если этот чек не пройдет неудачника — Kubernetes повернет этот POD от балансировки нагрузки/услуги
  • INationalDelayseconds : Давайте использовать 5 секунд здесь, чтобы начать PHP и подключиться к базе данных
  • Периодионные S: Как мы ожидаем проблем с соединениями базы данных — Давайте установим его до 5 секунд
  • FailureTheReshold : также три, как для ЛИЦИЛСПРОБА
  • SuccessthreShold : После того, как насколько успешная попытка подумайте о том, что POD готов к трафик — давайте настроим его на 1
  • Тайм-аутсекунды : по умолчанию 1, давайте использовать его

Посмотреть Настроить зонды Отказ

Обновлять зонды в развертывании:

...
        livenessProbe:
          httpGet:
            path: {{ .Values.appConfig.healthcheckPath }}
            port: {{ .Values.appConfig.port }}
          initialDelaySeconds: 5
          failureThreshold: 3
          periodSeconds: 15
        readinessProbe:
          httpGet: 
            path: {{ .Values.appConfig.readycheckPath }}
            port: {{ .Values.appConfig.port }}
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3
          successThreshold: 1
          timeoutSeconds: 1
...

Позже переместит его к Значения.yaml Отказ

И добавьте новую переменную для сервера базы данных ведомого:

...
        - name: DB\_WRITE\_HOST
          value: {{ .Values.appConfig.db.writeHost }}              
        - name: DB\_READ\_HOST
          value: {{ .Values.appConfig.db.readHost }}
...

Kubernetes: журналы PHP от Docker

Ах, и бревно!.

Разработчики включали журналы, которые будут отправлены на /dev/stderr Вместо того, чтобы писать в файл, а демон Docker должен получить их и отправить его в Кубернаны — но в kubectl logs Мы можем видеть сообщения только из Nginx.

Перейти, чтобы проверить Linux: PHP-FPM, Docker, STDOUT и STDERR — Нет журналов ошибок приложения Напомним, как это работает и перейдите к проверке дескрипторов.

В POD найдите PID Master’s Php-Process:

bash-4.4# ps aux |grep php-fpm | grep master
root 9 0.0 0.2 171220 20784 ? S 12:00 0:00 php-fpm: master process (/etc/php/7.1/php-fpm.conf)

И проверять его дескрипторы:

bash-4.4# ls -l /proc/9/fd/2
l-wx — — — 1 root root 64 Aug 21 12:04 /proc/9/fd/2 -> /var/log/php/7.1/php-fpm.log

bash-4.4# ls -l /proc/9/fd/1
lrwx — — — 1 root root 64 Aug 21 12:04 /proc/9/fd/1 -> /dev/null

FD/2 Это Стдерр процесса, и он сопоставлен на /var/log/php/7.1/php-fpm.log вместо /dev/stderr — Вот почему мы ничего не видим в логах Kubectl.

REREP The «/var/log/php/7.1/php-fpm.log» рекурсивно в /etc/php/7.1 каталог и найти php-fpm.conf какой по умолчанию есть Ошибка \ _log =/var/log/php/7.1/php-fpm.log Отказ Исправить это к /dev/stderr — И это сделано.

Запустите тест снова!

От 1 до 15.000 пользователей в течение 30 минут.

Первый тест

3300 пользователей — все хорошо:

Стручки:

kk -n eks-dev-1-eat-backend-ns top pod
NAME CPU(cores) MEMORY(bytes)
eat-backend-867b59c4dc-742vf 856m 325Mi
eat-backend-867b59c4dc-bj74b 623m 316Mi
eat-backend-867b59c4dc-cq5gd 891m 319Mi
eat-backend-867b59c4dc-mm2ll 600m 310Mi
eat-ackend-867b59c4dc-x8b8d 679m 313Mi
eat-backend-memcached-0 19m 68Mi

HPA:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 30%/30% 4 40 5 20h

На 7.000 пользователей мы получили новые ошибки — « php_network_getAddresses: getAddrinfo не удалось » — мои старые «друзья», столкнулись с на aws пару раз:

[2020–08–21 14:14:59] local.ERROR: SQLSTATE[HY000] [2002] php\_network\_getaddresses: getaddrinfo failed: Try again (SQL: insert into `order_logs` (`order_id`, `action`, `data`, `updated_at`, `created_at`) values (175951, nav, "Result page: ok", 2020–08–21 14:14:54, 2020–08–21 14:14:54)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 2002): SQLSTATE[HY000] [2002] php\_network\_getaddresses: getaddrinfo failed: Try again (SQL: insert into `order_logs` (`order_id`, `action`, `data`, `updated_at`, `created_at`) values (175951, nav, \"Result page: ok\", 2020–08–21 14:14:54, 2020–08–21 14:14:54))

Короче говоря — « php_network_getaddresses: hetAddrinfo failed » ошибка в AWS может произойти на три (по крайней мере, известные мной) причины:

Мы будем говорить о причине в нашем текущем случае немного позже в этом посте.

На 9 000+ PODS начал перезапустить:

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-867b59c4dc-2m7fd 0/1 Running 2 4m17s
eat-backend-867b59c4dc-742vf 0/1 CrashLoopBackOff 5 68m
eat-backend-867b59c4dc-bj74b 1/1 Running 5 68m
…
eat-backend-867b59c4dc-w24pz 0/1 CrashLoopBackOff 5 19m
eat-backend-867b59c4dc-x8b8d 0/1 CrashLoopBackOff 5 68m
eat-backend-memcached-0 1/1 Running 0 21h

Потому что они наклонились ответы на Livy и готовность проверки:

0s Warning Unhealthy Pod Readiness probe failed: Get [http://10.3.62.195:80/readiness:](http://10.3.62.195:80/readiness:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)
0s Warning Unhealthy Pod Liveness probe failed: Get [http://10.3.56.206:80/healthz:](http://10.3.56.206:80/healthz:) net/http: request canceled (Client.Timeout exceeded while awaiting headers)

А после 10 000 наших серверов базы данных начал отказываться от подключений:

[2020–08–21 13:05:11] production.ERROR: SQLSTATE[HY000] [2002] Connection refused {"exception":"[object] (Doctrine\\DBAL\\Driver\\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused at /var/www/new-eat-backend/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection refused

php_network_getaddresses: getAddrinfo не удалось и DNS

Итак, какие проблемы мы нашли на этот раз:

  • Ошибка: sqlstate [y000] [2002] Соединение отказано
  • php_network_getaddresses: hetAddrinfo не удалось

«Ошибка« »: SQLState [y000] [2002] Соединение отказалось от » — это известная проблема, и мы знаем, как иметь дело — я обновит экземпляр RDS из T3.Medium. к R5.large , но как насчет вопроса DNS?

Поскольку по причинам, упомянутых выше — пакеты в секунду на сетевом интерфейсе, пропускной способности сетевой ссылки и AWS VPC DNS, самым жизнеспособным, кажется, является сервис DNS: каждый раз, когда наша приложение хочет подключиться к серверу базы данных — это делает DNS-запрос для определения IP-сервера DB, а также все другие записи DNS и вместе они могут заполнить запросы 1024 в секунду.

Кстати, посмотрите на Графана: Loki — прометеузные счетчики logql, функции агрегации и диаграммы запросов DNSMAMSQ сообщение.

Давайте проверим настройки DNS наших стручков сейчас:

bash-4.4# cat /etc/resolv.conf
nameserver 172.20.0.10
search eks-dev-1-eat-backend-ns.svc.cluster.local svc.cluster.local cluster.local us-east-2.compute.internal
options ndots:5

ИНТЕРЕРВЕРС 172.20.0.10 — Должно быть наш Kube-DNS :

bash-4.4# nslookup 172.20.0.10
10.0.20.172.in-addr.arpa name = kube-dns.kube-system.svc.cluster.local.

Да это так.

И кстати, он сказал нам в ИТ-ложках, что он не может подключиться к API-серверу:

E0805 21: 32: 40.283128 1 Reflector.go: 283] PKG/MOD/K8S.IO/ Client-go@v0.0.0 -20190620085101-78D20085101-78D2AF792BAB/Tools/Cache/Reflector.go: 98: не удалось посмотреть * V1.Namepace: Get https://172.20.0.1:443/api/v1/namepaces?Resourceversion=23502628&timeout=9m40s&timeoutseconds=580&watch=true: Наберите TCP 172.20.0.1:443: Connect: Connection отказался

Итак, что мы можем сделать, чтобы предотвратить чрезмерное использование AWS VPC DNS?

  • Разорвать dnsmasq ? Для Kubernetes, кажется, немного странно, сначала — потому что kubernetes уже есть свои DNS, а во-вторых — я уверен, что мы не самые первые, кто столкнулся с этим вопросом, и я сомневаюсь, что они решили его с помощью дополнительного контейнера с dnsmasq (Тем не менее — проверьте dnsmasq: aws — «Временная ошибка в разрешении имени», logs, debug и dnsmasq кэш-размер )
  • Другое решение может быть использовано DNS от CloudFlare ( 1.1.1.1 ) или Google ( 8.8.8.8) — Тогда мы остановлюсь использовать VPC DNS вообще, но приведут увеличение времени отклика DNS

Кубернаны dnspolicy.

Хорошо, давайте посмотрим, как DNS настроен в Kubernetes в целом:

Примечание: Вы можете управлять конфигурацией DNS вашего POD с Dnspolicy поле в спецификации стручки. Если это поле не заполнено, то ClusterFirst Политика DNS используется по умолчанию.

Итак, по умолчанию для стручек ClusterFirst установлен, который:

Любой запрос DNS, который не соответствует настроенному суффиксу домена кластера, таких как «www.kubernetes.io», пересылается на вышестоящий имен, унаследованный от узла.

И, очевидно, AWS EC2 по умолчанию будет использовать именно AWS VPC DNS.

Смотрите также — Как устранить неполадки DNS сбои с Amazon EKS?

Узлы DNS могут быть настроены с помощью настроек кластераутоскалеров:

$ kk -n kube-system get pod cluster-autoscaler-5dddc9c9b-fstft -o yaml
…
spec:
containers:
- command:
- ./cluster-autoscaler
- — v=4
- — stderrthreshold=info
- — cloud-provider=aws
- — skip-nodes-with-local-storage=false
- — expander=least-waste
- — node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/bttrm-eks-dev-1
- — balance-similar-node-groups
- — skip-nodes-with-system-pods=false
…

Но в нашем случае здесь ничто не было изменено, все осталось со своими настройками по умолчанию.

Запуск DNS NODELOCAL в Куберате

Но идея с dnsmasq Был правильным, но для Кубератесов есть Odelocal dns Решение, которое является именно той же службой кэширования, что и DNSMASQ, но он будет использовать Kube-DNS захватить записи, а Kube-DNS пойдем в VPC DNS позже.

Что нам нужно, чтобы запустить его:

  • Kubedns : займет kubectl Get SVC Kube-DNS -N Kube-System -o jsonpath = {. SPEC.CLUSTERIP} команда
  • Домен : Является ли наше, Cluster.local
  • localdns : адрес, где будет доступно локальный кэш DNS-кэш, давайте использовать 169.254.20.10

Получить Kube-DNS Сервис IP:

$ kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}
172.20.0.10

Смотрите также Фиксация EKS DNS Отказ

Скачать . odelocaldns.yaml файл:

$ wget [https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml](https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml)

Обновите его с помощью SED и установленные данные, которые мы определяли выше:

$ sed -i "s/\_\_PILLAR\_\_LOCAL\_\_DNS\_\_/169.254.20.10/g; s/\_\_PILLAR\_\_DNS\_\_DOMAIN\_\_/cluster.local/g; s/\_\_PILLAR\_\_DNS\_\_SERVER\_\_/172.20.0.10/g" nodelocaldns.yaml

Проверьте содержание манифеста — что это сделает — здесь kubernetes Daemonset Будет создан, что раскрутит стручки с DNS NODELOCAL на каждом доменоде Kubernetes:

...
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-local-dns
...

И его Configmap :

...
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: node-local-dns
  namespace: kube-system
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
data:
  Corefile: |
    cluster.local:53 {
        errors
        cache {
                success 9984 30
                denial 9984 5
        }
        reload
        loop
        bind 169.254.20.10 172.20.0.10
        forward . \_\_PILLAR\_\_CLUSTER\_\_DNS\_\_ {
                force\_tcp
        }
        prometheus :9253
        health 169.254.20.10:8080
        }

...

Развернуть это:

$ kubectl apply -f nodelocaldns.yaml
serviceaccount/node-local-dns created
service/kube-dns-upstream created
configmap/node-local-dns created
daemonset.apps/node-local-dns created

Проверьте стручки:

$ kk -n kube-system get pod | grep local-dns
node-local-dns-7cndv 1/1 Running 0 33s
node-local-dns-7hrlc 1/1 Running 0 33s
node-local-dns-c5bhm 1/1 Running 0 33s

Его обслуживание:

$ kk -n kube-system get svc | grep dns
kube-dns ClusterIP 172.20.0.10  53/UDP,53/TCP 88d
kube-dns-upstream ClusterIP 172.20.245.211  53/UDP,53/TCP 107s

Kube-DNS-Upstream Clusterip 172.20.245.21 , но из наших стручков он должен быть доступен по 169.254.20.10 IP, как мы устанавливаем в localdns Отказ

Это работает? Перейти к чеку из стручка:

bash-4.4# dig @169.254.20.10 ya.ru +short
87.250.250.242

Ага , работает, хорошо.

Следующая вещь, чтобы переконфигурировать наши стручки, чтобы они использовали 169.254.20.10 вместо Kube-DNS Оказание услуг.

В Экктл Файл конфигурации это можно сделать с помощью Clusterdns :

...
nodeGroups:
- name: mygroup
    clusterDNS: 169.254.20.10
...

Но тогда вам нужно обновить (на самом деле — воссоздать) ваши существующие рабочие узлы.

Kubernetes Pod dnsconfig && именные серверы

Чтобы применить изменения без создания групп на рабочихернах — мы можем указать необходимые настройки DNS в нашем развертывании, добавив dnsconfig и именные серверы :

...
        resources:
          requests:
            cpu: 2500m
            memory: 500m
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsConfig:
        nameservers:
        - 169.254.20.10
      dnsPolicy: None
      imagePullSecrets:
      - name: gitlab-secret
      nodeSelector:
        beta.kubernetes.io/instance-type: c5.xlarge
        role: eat-workers
...

Развертывание, проверка:

$ kk -n eks-dev-1-eat-backend-ns exec -ti eat-backend-f7b49b4b7–4jtk5 cat /etc/resolv.conf
nameserver 169.254.20.10

Хорошо…

Это работает?

Давайте проверим с копать от стручка:

$ kk -n eks-dev-1-eat-backend-ns exec -ti eat-backend-f7b49b4b7–4jtk5 dig ya.ru +short
87.250.250.242

Да, все хорошо.

Теперь мы можем выполнить второй тест.

Результаты первого теста были следующими:

Когда у нас есть ошибки после 8.000 пользователей.

Второй тест

8500 — все хорошо до сих пор:

На предыдущем тесте мы начали получать ошибки после 7.000 — около 150-200 ошибок, а в это время только 5 ошибок.

Статус Pods:

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-5d8984656–2ftd6 1/1 Running 0 17m
eat-backend-5d8984656–45xvk 1/1 Running 0 9m11s
eat-backend-5d8984656–6v6zr 1/1 Running 0 5m10s
…
eat-backend-5d8984656-th2h6 1/1 Running 0 37m
eat-backend-memcached-0 1/1 Running 0 24h

НРА:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 32%/30% 4 40 13 24h

10.000 — все еще хорошо:

НРА:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 30%/30% 4 40 15 24h

Стручки:

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-5d8984656–2ftd6 1/1 Running 0 28m
eat — backend-5d8984656–45xvk 1/1 Running 0 20m
eat-backend-5d8984656–6v6zr 1/1 Running 0 16m
…
eat-backend-5d8984656-th2h6 1/1 Running 0 48m
eat-backend-5d8984656-z2tpp 1/1 Running 0 3m51s
eat-backend-memcached-0 1/1 Running 0 24h

Подключается к серверу базы данных:

Узлы:

$ kk top node -l role=eat-workers
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10–3–39–145.us-east-2.compute.internal 743m 18% 1418Mi 24%
ip-10–3–44–14.us-east-2.compute.internal 822m 20% 1327Mi 23%
…
ip-10–3–62–143.us-east-2.compute.internal 652m 16% 1259Mi 21%
ip-10–3–63–96.us-east-2.compute.internal 664m 16% 1266Mi 22%
ip-10–3–63–186.us-east-2.compute.internal    
ip-10–3–58–180.us-east-2.compute.internal    
…
ip-10–3–51–254.us-east-2.compute.internal    

Автоскалинг все еще работает, все хорошо:

В 17:45 было время отклика, а пару ошибок — но потом все пошло нормально.

Нет Pods перезагрузится:

$ kk -n eks-dev-1-eat-backend-ns get pod
NAME READY STATUS RESTARTS AGE
eat-backend-5d8984656–2ftd6 1/1 Running 0 44m
eat-backend-5d8984656–45xvk 1/1 Running 0 36m
eat-backend-5d8984656–47vp9 1/1 Running 0 6m49s
eat-backend-5d8984656–6v6zr 1/1 Running 0 32m
eat-backend-5d8984656–78tq9 1/1 Running 0 2m45s
…
eat-backend-5d8984656-th2h6 1/1 Running 0 64m
eat-backend-5d8984656-vbzhr 1/1 Running 0 6m49s
eat-backend-5d8984656-xzv6n 1/1 Running 0 6m49s
eat-backend-5d8984656-z2tpp 1/1 Running 0 20m
eat-backend-5d8984656-zfrb7 1/1 Running 0 16m
eat-backend-memcached-0 1/1 Running 0 24h

30 стручек были расширены:

$ kk -n eks-dev-1-eat-backend-ns get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
eat-backend-hpa Deployment/eat-backend 1%/30% 4 40 30 24h

0% ошибок:

Apache jmeter è grafana

Наконец, я впервые увидел такое решение, и это выглядит действительно хорошо — команда QA сделала свой JMeter CTO прислать результаты тестирования в IncoluxDB, а затем Grafana использует его, чтобы нарисовать графики:

Первоначально опубликовано в RTFM: Linux, DevOps и системное управление Отказ

Оригинал: «https://dev.to/setevoy/kubernetes-load-testing-and-high-load-tuning-problems-and-solutions-2o45»