Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.
Запуск застосунків
- 1: Запуск застосунку без збереження стану за допомогою Deployment
- 2: Запуск одноекземплярного застосунку зі збереженням стану
- 3: Запуск реплікованого застосунку зі збереженням стану
- 4: Масштабування StatefulSet
- 5: Видалення StatefulSet
- 6: Примусове видалення Podʼів StatefulSet
- 7: Горизонтальне автомасштабування Podʼів
- 8: Покрокове керівництво HorizontalPodAutoscaler
- 9: Вказання бюджету розладів для вашого застосунку
- 10: Отримання доступу до API Kubernetes з Pod
1 - Запуск застосунку без збереження стану за допомогою Deployment
Ця сторінка показує, як запустити застосунок за допомогою обʼєкта Deployment в Kubernetes.
Цілі
- Створити розгортання nginx.
- Використання kubectl для виведення інформації про розгортання.
- Оновити розгортання.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж v1.9. Для перевірки версії введітьkubectl version
.Створення та дослідження розгортання nginx
Ви можете запустити застосунок, створивши обʼєкт Kubernetes Deployment, і ви можете описати Deployment у файлі YAML. Наприклад, цей файл YAML описує Deployment, який використовує образ Docker nginx:1.14.2:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # вказує Deployment запустити 2 Podʼи, що відповідають шаблону
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Створіть Deployment на основі файлу YAML:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
Виведіть інформацію про Deployment:
kubectl describe deployment nginx-deployment
Вивід схожий на:
Name: nginx-deployment Namespace: default CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700 Labels: app=nginx Annotations: deployment.kubernetes.io/revision=1 Selector: app=nginx Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge Pod Template: Labels: app=nginx Containers: nginx: Image: nginx:1.14.2 Port: 80/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created) No events.
Перегляньте Podʼи, створені розгортанням:
kubectl get pods -l app=nginx
Вивід схожий на:
NAME READY STATUS RESTARTS AGE nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h nginx-deployment-1771418926-r18az 1/1 Running 0 16h
Виведіть інформацію про Pod:
kubectl describe pod <pod-name>
де
<pod-name>
— це імʼя одного з ваших Podʼів.
Оновлення розгортання
Ви можете оновити розгортання, застосувавши новий файл YAML. Цей файл YAML вказує, що розгортання повинне бути оновлене до nginx 1.16.1.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # Оновлення версії nginx з 1.14.2 до 1.16.1
ports:
- containerPort: 80
Застосуйте новий файл YAML:
kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
Спостерігайте, як розгортання створює Podʼи з новими іменами і видаляє старі Podʼи:
kubectl get pods -l app=nginx
Масштабування застосунку шляхом збільшення кількості реплік
Ви можете збільшити кількість Podʼів у вашому Deployment, застосувавши новий YAML файл. Цей файл YAML встановлює replicas
на 4, що вказує, що Deployment повиннен мати чотири Podʼи:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 4 # Update the replicas from 2 to 4
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1
ports:
- containerPort: 80
Застосуйте новий файл YAML:
kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
Перевірте, що Deployment має чотири Podʼи:
kubectl get pods -l app=nginx
Вивід схожий на:
NAME READY STATUS RESTARTS AGE nginx-deployment-148880595-4zdqq 1/1 Running 0 25s nginx-deployment-148880595-6zgi1 1/1 Running 0 25s nginx-deployment-148880595-fxcez 1/1 Running 0 2m nginx-deployment-148880595-rwovn 1/1 Running 0 2m
Видалення Deployment
Видаліть Deployment за іменем:
kubectl delete deployment nginx-deployment
ReplicationControllers — Старий спосіб
Перевагою створення реплікованих застосунків є використання Deployment, який своєю чергою використовує ReplicaSet. До того, як в Kubernetes були додані Deployment та ReplicaSet, репліковані застосунки конфігурувалися за допомогою ReplicationController.
Що далі
- Дізнайтеся більше про обʼєкти Deployment.
2 - Запуск одноекземплярного застосунку зі збереженням стану
На цій сторінці показано, як запустити одноекземплярний застосунок зі збереженням стану (Stateful) в Kubernetes, використовуючи PersistentVolume та Deployment. Застосунок — MySQL.
Цілі
- Створити PersistentVolume, посилаючись на диск у вашому середовищі.
- Створити Deployment MySQL.
- Використання MySQL для інших Podʼів в кластері за відомим DNS-імʼям.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Для перевірки версії введітьkubectl version
.Вам потрібно мати або динамічний провізор PersistentVolume з типовим StorageClass, або статично надавати PersistentVolume самостійно, щоб задовольнити PersistentVolumeClaims, що використовується тут.
Розгортання MySQL
Ви можете запустити stateful застосунок, створивши Deployment Kubernetes та підʼєднавши його до наявного PersistentVolume за допомогою PersistentVolumeClaim. Наприклад, цей файл YAML описує Deployment, що запускає MySQL та посилається на PersistentVolumeClaim. Файл визначає монтування тому для /var/lib/mysql
, а потім створює PersistentVolumeClaim, який шукає том 20G. Ця заявка виконується будь-яким наявним томом, який відповідає вимогам, або за допомогою динамічного провізора.
Примітка: пароль визначений в файлі конфігурації yaml, і це не є безпечним. Див. Kubernetes Secrets для безпечнішого рішення.
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
# Використання secret у реальному використанні
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
Розгорніть PV та PVC з файлу YAML:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
Розгорніть вміст файлу YAML:
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
Показати інформацію про Deployment:
kubectl describe deployment mysql
Вивід схожий на:
Name: mysql Namespace: default CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700 Labels: app=mysql Annotations: deployment.kubernetes.io/revision=1 Selector: app=mysql Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable StrategyType: Recreate MinReadySeconds: 0 Pod Template: Labels: app=mysql Containers: mysql: Image: mysql:5.6 Port: 3306/TCP Environment: MYSQL_ROOT_PASSWORD: password Mounts: /var/lib/mysql from mysql-persistent-storage (rw) Volumes: mysql-persistent-storage: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: mysql-pv-claim ReadOnly: false Conditions: Type Status Reason ---- ------ ------ Available False MinimumReplicasUnavailable Progressing True ReplicaSetUpdated OldReplicaSets: <none> NewReplicaSet: mysql-63082529 (1/1 replicas created) Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
Перегляньте Podʼи, створені Deployment:
kubectl get pods -l app=mysql
Вивід схожий на:
NAME READY STATUS RESTARTS AGE mysql-63082529-2z3ki 1/1 Running 0 3m
Перевірка PersistentVolumeClaim:
kubectl describe pvc mysql-pv-claim
Вивід схожий на:
Name: mysql-pv-claim Namespace: default StorageClass: Status: Bound Volume: mysql-pv-volume Labels: <none> Annotations: pv.kubernetes.io/bind-completed=yes pv.kubernetes.io/bound-by-controller=yes Capacity: 20Gi Access Modes: RWO Events: <none>
Доступ до екземпляра MySQL
Попередній YAML-файл створює Service, який дозволяє іншим Podʼам в кластері отримувати доступ до бази даних. Опція Service clusterIP: None
дозволяє імені DNS Serviceʼа безпосередньо посилатись на IP-адресу Podʼа. Це оптимально, коли у вас є лише один Pod за Service і ви не маєте наміру збільшувати кількість Podʼів.
Запустіть клієнта MySQL, щоб підʼєднатися до сервера:
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
Ця команда створює новий Pod у кластері, що виконує клієнта MySQL та підʼєднується до сервера через Service. Якщо підʼєднання вдалося, ви знаєте, що ваша stateful база даних MySQL працює.
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
mysql>
Оновлення
Образ або будь-яку іншу частину Deployment можна оновити як зазвичай за допомогою команди kubectl apply
. Ось деякі заходи обережності, які специфічні для застосунків зі збереженням стану:
- Не масштабуйте застосунок. Цей варіант призначений лише для застосунків з одним екземпляром. Основний PersistentVolume можна примонтувати лише до одного Podʼа. Для кластеризованих застосунків зі збереженням стану див. документацію StatefulSet.
- Використовуйте
strategy:
type: Recreate
в файлі конфігурації YAML Deployment. Це вказує Kubernetes не використовувати постійні (rolling) оновлення. Такі оновлення не працюватимуть, оскільки ви не можете мати більше одного Podʼа, що працює одночасно. СтратегіяRecreate
зупинить перший Pod перед створенням нового з оновленою конфігурацією.
Видалення Deployment
Видаліть розгорнуті обʼєкти за іменем:
kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv-volume
Якщо ви вручну вказували PersistentVolume, вам також потрібно вручну видалити його, а також звільнити основний ресурс. Якщо ви використовували динамічного провізора, він автоматично видаляє PersistentVolume, коли бачить, що ви видалили PersistentVolumeClaim. Деякі динамічні провізори (наприклад, ті, що стосуються EBS та PD) також звільняють основний ресурс після видалення PersistentVolume.
Що далі
Дізнайтеся більше про обʼєкти Deployment.
Дізнайтеся більше про розгортання застосунків
3 - Запуск реплікованого застосунку зі збереженням стану
Ця сторінка показує, як запустити реплікований застосунок зі збереженням стану (StatefulSet). Цей застосунок — реплікована база даних MySQL. У топології цього прикладу є один головний сервер і кілька реплік, що використовують асинхронну реплікацію на основі рядків.
Примітка:
Ця конфігурація не для операційної експлуатації. Налаштування MySQL залишаються на небезпечних стандартних значеннях, щоб зосередитися на загальних патернах запуску застосунків зі збереженням стану в Kubernetes.Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Вам потрібно мати або динамічний провізор PersistentVolume з типовим StorageClass, або статично надавати PersistentVolume самостійно, щоб задовольнити PersistentVolumeClaims, що використовується тут.
- Це завдання передбачає, що ви знаєте про Постійні томи та StatefulSets, а також інші основні поняття, такі як Pod, Service та ConfigMap.
- Трохи знань MySQL корисні, але цей посібник має на меті представити загальні патерни, які можуть бути корисними для інших систем.
- Ви використовуєте простір імен default або інший простір імен, в якому відсутні обʼєкти, що конфліктують.
- У вас має бути AMD64-сумісний процесор.
Цілі
- Розгорнути репліковану топологію MySQL за допомогою StatefulSet.
- Направити трафік від клієнта MySQL.
- Спостерігати стійкість до перерв у роботі.
- Масштабувати StatefulSet вгору та вниз.
Розгортання MySQL
Приклад розгортання складається з ConfigMap, двох Service та StatefulSet.
Створення ConfigMap
Створіть ConfigMap із наступного файлу конфігурації YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
labels:
app: mysql
app.kubernetes.io/name: mysql
data:
primary.cnf: |
# Застосовує цю конфігурацію до primary.
[mysqld]
log-bin
replica.cnf: |
# Застосовує цю конфігурацію до реплік.
[mysqld]
super-read-only
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-configmap.yaml
Цей ConfigMap надає перевизначення для my.cnf
, що дозволяє вам незалежно керувати конфігурацією на головному сервері MySQL та його репліках. У цьому випадку ви хочете, щоб головний сервер міг обслуговувати логи реплікацій реплік, а репліки відхиляли будь-які записи, які надходять не через реплікацію.
Немає нічого особливого у самому ConfigMap, що зумовлює застосування різних частин до різних Podʼів. Кожен Pod вирішує, яку частину дивитися при ініціалізації, на основі інформації, що надає контролер StatefulSet.
Створення Service
Створіть Service із наступного файлу конфігурації YAML:
# Service headless для стабільних записів DNS членів StatefulSet.
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
app.kubernetes.io/name: mysql
spec:
ports:
- name: mysql
port: 3306
clusterIP: None
selector:
app: mysql
---
# Service клієнт для підʼєднання до екземпляру MySQL для читання.
# Для запису ви повинні підключитися до основного: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
name: mysql-read
labels:
app: mysql
app.kubernetes.io/name: mysql
readonly: "true"
spec:
ports:
- name: mysql
port: 3306
selector:
app: mysql
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-services.yaml
Service headless надає місце для DNS-записів, які контролери StatefulSet створюють для кожного Podʼа, що є частиною набору. Оскільки headless Service називається mysql
, Podʼи доступні за допомогою зіставлення <pod-name>.mysql
з будь-якого іншого Podʼа в тому ж Kubernetes кластері та просторі імен.
Клієнтський Service, з назвою mysql-read
, є звичайним Service з власним кластерним IP, який розподіляє підключення між всіма Podʼами MySQL, які повідомляють про готовність. Набір потенційних точок доступу включає головний сервер MySQL та всі репліки.
Зверніть увагу, що лише запити на читання можуть використовувати балансувальник Service. Оскільки існує лише один головний сервер MySQL, клієнти повинні підключатися безпосередньо до головного Podʼа MySQL (через його DNS-запис у головному Service) для виконання записів.
Створення StatefulSet
Наостанок, створіть StatefulSet із наступного файлу конфігурації YAML:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
app.kubernetes.io/name: mysql
serviceName: mysql
replicas: 3
template:
metadata:
labels:
app: mysql
app.kubernetes.io/name: mysql
spec:
initContainers:
- name: init-mysql
image: mysql:5.7
command:
- bash
- "-c"
- |
set -ex
# Generate mysql server-id from pod ordinal index.
[[ $HOSTNAME =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# Add an offset to avoid reserved server-id=0 value.
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# Copy appropriate conf.d files from config-map to emptyDir.
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/primary.cnf /mnt/conf.d/
else
cp /mnt/config-map/replica.cnf /mnt/conf.d/
fi
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
- name: config-map
mountPath: /mnt/config-map
- name: clone-mysql
image: gcr.io/google-samples/xtrabackup:1.0
command:
- bash
- "-c"
- |
set -ex
# Skip the clone if data already exists.
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Skip the clone on primary (ordinal index 0).
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# Clone data from previous peer.
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# Prepare the backup.
xtrabackup --prepare --target-dir=/var/lib/mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "1"
ports:
- name: mysql
containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
# Перевіряє, чи можемо ми виконувати запити через TCP (skip-networking вимкнено).
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
- name: xtrabackup
image: gcr.io/google-samples/xtrabackup:1.0
ports:
- name: xtrabackup
containerPort: 3307
command:
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql
# Determine binlog position of cloned data, if any.
if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# XtraBackup already generated a partial "CHANGE MASTER TO" query
# because we're cloning from an existing replica. (Need to remove the tailing semicolon!)
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# Ignore xtrabackup_binlog_info in this case (it's useless).
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[ -f xtrabackup_binlog_info ]]; then
# We're cloning directly from primary. Parse binlog position.
[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi
# Check if we need to complete a clone by starting replication.
if [[ -f change_master_to.sql.in ]]; then
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
echo "Initializing replication from clone position"
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# In case of container restart, attempt this at-most-once.
mv change_master_to.sql.in change_master_to.sql.orig
fi
# Start a server to send backups when requested by peers.
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 100m
memory: 100Mi
volumes:
- name: conf
emptyDir: {}
- name: config-map
configMap:
name: mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml
Ви можете спостерігати за процесом запуску, виконавши:
kubectl get pods -l app=mysql --watch
Через деякий час ви повинні побачити, що всі 3 Podʼи стануть Running
:
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 2m
mysql-1 2/2 Running 0 1m
mysql-2 2/2 Running 0 1m
Натисніть Ctrl+C, щоб скасувати перегляд.
Примітка:
Якщо ви не бачите жодних змін, переконайтеся, що у вас увімкнений динамічний PersistentVolume провізор, як зазначено у передумовах.Цей маніфест використовує різноманітні техніки для керування Podʼами як частиною StatefulSet. У наступному розділі підкреслено деякі з цих технік, щоб пояснити, що відбувається під час створення Podʼів StatefulSet.
Розуміння ініціалізації Podʼа зі збереженням стану
Контролер StatefulSet запускає Podʼи по одному, в порядку їх індексів. Він чекає, доки кожен Pod не повідомить про готовність, перш ніж запустити наступний.
Крім того, контролер призначає кожному Podʼу унікальне, стабільне імʼя у формі <statefulset-name>-<ordinal-index>
, в результаті отримуємо Podʼи з іменами mysql-0
, mysql-1
та mysql-2
.
Шаблон Podʼа у вищенаведеному маніфесті StatefulSet використовує ці властивості, щоб здійснити впорядкований запуск реплікації MySQL.
Створення конфігурації
Перед запуском будь-яких контейнерів у специфікації Podʼа, спочатку Pod запускає будь-які контейнери ініціалізації у визначеному порядку.
Перший контейнер ініціалізації, init-mysql
, генерує спеціальні конфігураційні файли MySQL на основі порядкового індексу.
Скрипт визначає свій власний порядковий індекс, витягуючи його з кінця імені Podʼа, яке повертається командою hostname
. Потім він зберігає порядковий індекс (з числовим зміщенням для уникнення зарезервованих значень) у файлі з назвою server-id.cnf
в теці conf.d
MySQL. Це перетворює унікальний, стабільний ідентифікатор, наданий StatefulSet, у домен ідентифікаторів серверів MySQL, які вимагають таких же властивостей.
Скрипт у контейнері init-mysql
також застосовує або primary.cnf
, або replica.cnf
з ConfigMap, копіюючи вміст у conf.d
. Оскільки у топології цього прикладу є лише один головний сервер MySQL та будь-яка кількість реплік, скрипт призначає порядковий індекс 0
головному серверу, а всі інші — репліками. Разом з гарантією контролера StatefulSet щодо порядку розгортання, це забезпечує готовність головного сервера MySQL перед створенням реплік, щоб вони могли почати реплікацію.
Клонування наявних даних
Загалом, коли новий Pod приєднується до набору як репліка, він повинен припускати, що головний сервер MySQL може вже містити дані. Також він повинен припускати, що логи реплікації можуть не бути повністю отримані з самого початку. Ці консервативні припущення є ключем до можливості запуску робочого StatefulSet масштабуватися вгору та вниз з часом, а не залишатися фіксованим на своєму початковому розмірі.
Другий контейнер ініціалізації, з назвою clone-mysql
, виконує операцію клонування на реплікаційному Podʼі першого разу, коли він запускається на порожньому PersistentVolume. Це означає, що він копіює всі наявні дані з іншого працюючого Podʼа, таким чином, його локальний стан є достатньо консистентним для початку реплікації з головного сервера.
MySQL сам по собі не надає механізму для цього, тому приклад використовує популярний відкритий інструмент — Percona XtraBackup. Під час клонування MySQL сервер може мати знижену продуктивність. Щоб мінімізувати вплив на головний сервер MySQL, скрипт вказує кожному Podʼу отримувати дані з Podʼа, чий порядковий індекс на одиницю менший. Це працює через те, що контролер StatefulSet завжди гарантує, що Pod N
є готовим перед запуском Podʼа N+1
.
Початок реплікації
Після успішного завершення контейнерів ініціалізації запускаються звичайні контейнери. Podʼи MySQL складаються з контейнера mysql
, в якому працює фактичний сервер mysqld
, та контейнера xtrabackup
, який діє як sidecar.
Sidecar xtrabackup
переглядає клоновані файли даних і визначає, чи необхідно ініціалізувати реплікацію MySQL на репліці. У цьому випадку він чекає, доки mysqld
буде готовий, а потім виконує команди CHANGE MASTER TO
та START SLAVE
з параметрами реплікації, отриманими з клонованих файлів XtraBackup.
Після того як репліка починає реплікацію, вона запамʼятовує свій головний сервер MySQL і автоматично підʼєднується, якщо сервер перезавантажується або зʼєднання втрачається. Також, оскільки репліки шукають головний сервер за його стабільним DNS-імʼям (mysql-0.mysql
), вони автоматично знаходять головний сервер навіть якщо він отримує новий IP Podʼа через перепланування.
Нарешті, після початку реплікації, контейнер xtrabackup
слухає зʼєднання з інших Podʼів, які запитують клон даних. Цей сервер залишається активним нескінченно довго в разі, якщо StatefulSet масштабується вгору, або якщо наступний Pod втрачає свій PersistentVolumeClaim і потрібно повторно виконати клонування.
Надсилання клієнтського трафіку
Ви можете надіслати тестові запити до головного сервера MySQL (хост mysql-0.mysql
) запустивши тимчасовий контейнер з образом mysql:5.7
і використовуючи бінарний файл клієнта mysql
.
kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\
mysql -h mysql-0.mysql <<EOF
CREATE DATABASE test;
CREATE TABLE test.messages (message VARCHAR(250));
INSERT INTO test.messages VALUES ('hello');
EOF
Використовуйте хост mysql-read
, щоб надіслати тестові запити до будь-якого сервера, який повідомляє про готовність:
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
mysql -h mysql-read -e "SELECT * FROM test.messages"
Ви повинні отримати вивід схожий на цей:
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
Щоб продемонструвати, що Service mysql-read
розподіляє підключення між
серверами, ви можете запустити SELECT @@server_id
у циклі:
kubectl run mysql-client-loop --image=mysql:5.7 -i -t --rm --restart=Never --\
bash -ic "while sleep 1; do mysql -h mysql-read -e 'SELECT @@server_id,NOW()'; done"
Ви повинні бачити, що @@server_id
змінюється випадковим чином, оскільки може бути вибрана інша точка доступу при кожній спробі підключення:
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 100 | 2006-01-02 15:04:05 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 102 | 2006-01-02 15:04:06 |
+-------------+---------------------+
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 101 | 2006-01-02 15:04:07 |
+-------------+---------------------+
Ви можете натиснути Ctrl+C, коли захочете зупинити цикл, але цікаво тримати його запущеним в іншому вікні, щоб бачити ефект від наступних кроків.
Симуляція відмови Podʼа та Вузла
Щоб продемонструвати підвищену доступність читання з пулу реплік замість одного сервера, залиште цикл SELECT @@server_id
, запущений вище, активним, тоді як ви змушуєте Pod вийти зі стану Ready.
Збій проби готовності
Проба готовності для контейнера mysql
виконує команду mysql -h 127.0.0.1 -e 'SELECT 1'
, щоб переконатися, що сервер запущений і може виконувати запити.
Одним зі способів змусити цю пробу готовності збоїти — це пошкодити цю команду:
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql /usr/bin/mysql.off
Ця дія втручається у файлову систему контейнера Podʼа mysql-2
і перейменовує команду mysql
, щоб проба готовності не могла її знайти. Через кілька секунд Pod повинен повідомити про один зі своїх контейнерів як неготовий, що можна перевірити за допомогою:
kubectl get pod mysql-2
Перевірте значення 1/2
у стовпці READY
:
NAME READY STATUS RESTARTS AGE
mysql-2 1/2 Running 0 3m
На цьому етапі ви повинні бачити продовження роботи вашого циклу SELECT @@server_id
, хоча він більше не повідомляє про 102
. Нагадаємо, що скрипт init-mysql
визначив server-id
як 100 + $ordinal
, тож ідентифікатор сервера 102
відповідає Поду mysql-2
.
Тепер відновіть Pod і він повинен знову зʼявитися у виводі циклу через кілька секунд:
kubectl exec mysql-2 -c mysql -- mv /usr/bin/mysql.off /usr/bin/mysql
Видалення Podʼів
Контролер StatefulSet також створює Podʼи знову, якщо вони видалені, подібно до того, як це робить ReplicaSet для Podʼів без збереження стану.
kubectl delete pod mysql-2
Контролер StatefulSet помічає, що Podʼа mysql-2
більше не існує, і створює новий з тією ж назвою та повʼязаний з тим самим PersistentVolumeClaim. Ви повинні побачити, що ідентифікатор сервера 102
зникне з виводу циклу протягом певного часу і потім повернеться самостійно.
Виведення вузла з експлуатації
Якщо у вашому кластері Kubernetes є кілька вузлів, ви можете симулювати відмову вузла(наприклад, під час оновлення вузлів) за допомогою команди drain.
Спочатку визначте, на якому вузлі знаходиться один із Podʼів MySQL:
kubectl get pod mysql-2 -o wide
Назва вузла повинна зʼявитися у останньому стовпчику:
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Running 0 15m 10.244.5.27 kubernetes-node-9l2t
Потім виведіть вузол з експлуатації, виконавши наступну команду, яка забороняє новим Podʼам запускатися на цьому вузлі та видаляє будь-які існуючі Podʼи. Замість <node-name>
підставте назву вузла, яку ви знайшли на попередньому кроці.
Увага:
Виведення вузла з експлуатації може вплинути на інші завдання та застосунки, що працюють на тому ж вузлі. Виконуйте наступний крок тільки на тестовому кластері.# Дивіться вище поради щодо впливу на інші завдання
kubectl drain <node-name> --force --delete-emptydir-data --ignore-daemonsets
Тепер ви можете спостерігати, як Pod переплановується на іншому вузлі:
kubectl get pod mysql-2 -o wide --watch
Це має виглядати приблизно так:
NAME READY STATUS RESTARTS AGE IP NODE
mysql-2 2/2 Terminating 0 15m 10.244.1.56 kubernetes-node-9l2t
[...]
mysql-2 0/2 Pending 0 0s <none> kubernetes-node-fjlm
mysql-2 0/2 Init:0/2 0 0s <none> kubernetes-node-fjlm
mysql-2 0/2 Init:1/2 0 20s 10.244.5.32 kubernetes-node-fjlm
mysql-2 0/2 PodInitializing 0 21s 10.244.5.32 kubernetes-node-fjlm
mysql-2 1/2 Running 0 22s 10.244.5.32 kubernetes-node-fjlm
mysql-2 2/2 Running 0 30s 10.244.5.32 kubernetes-node-fjlm
І знову, ви повинні побачити, що ідентифікатор сервера 102
зник з виводу циклу SELECT @@server_id
протягом певного часу, а потім повернувся.
Тепер знову дозвольте вузлу приймати навантаження:
kubectl uncordon <node-name>
Масштабування кількості реплік
Коли ви використовуєте реплікацію MySQL, ви можете збільшувати кількість запитів на читання, додаючи репліки. Для StatefulSet це можна зробити однією командою:
kubectl scale statefulset mysql --replicas=5
Спостерігайте, як нові Podʼи запускаються, виконавши:
kubectl get pods -l app=mysql --watch
Коли вони будуть готові, ви побачите, що ідентифікатори серверів 103
та 104
починають зʼявлятися у виводі циклу SELECT @@server_id
.
Ви також можете перевірити, що ці нові сервери мають дані, які ви додали до них до того, як вони існували:
kubectl run mysql-client --image=mysql:5.7 -i -t --rm --restart=Never --\
mysql -h mysql-3.mysql -e "SELECT * FROM test.messages"
Waiting for pod default/mysql-client to be running, status is Pending, pod ready: false
+---------+
| message |
+---------+
| hello |
+---------+
pod "mysql-client" deleted
Зменшити кількість реплік також можна однією командою:
kubectl scale statefulset mysql --replicas=3
Примітка:
Хоча збільшення створює нові PersistentVolumeClaims автоматично, зменшення автоматично не видаляє ці PVC.
Це дає вам можливість залишити ці ініціалізовані PVC для швидшого збільшення, або вилучити дані перед їх видаленням.
Ви можете перевірити це, виконавши:
kubectl get pvc -l app=mysql
Це покаже, що всі 5 PVC все ще існують, попри те, що StatefulSet був зменшений до 3:
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
data-mysql-0 Bound pvc-8acbf5dc-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-1 Bound pvc-8ad39820-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-2 Bound pvc-8ad69a6d-b103-11e6-93fa-42010a800002 10Gi RWO 20m
data-mysql-3 Bound pvc-50043c45-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
data-mysql-4 Bound pvc-500a9957-b1c5-11e6-93fa-42010a800002 10Gi RWO 2m
Якщо ви не збираєтеся повторно використовувати додаткові PVC, ви можете їх видалити:
kubectl delete pvc data-mysql-3
kubectl delete pvc data-mysql-4
Очищення
Припинить цикл
SELECT @@server_id
, натиснувши Ctrl+C в його терміналі або виконавши наступне з іншого терміналу:kubectl delete pod mysql-client-loop --now
Видаліть StatefulSet. Це також розпочне завершення Podʼів.
kubectl delete statefulset mysql
Перевірте, що Podʼи зникають. Вони можуть зайняти деякий час для завершення роботи.
kubectl get pods -l app=mysql
Ви будете знати, що Podʼи завершилися, коли вищезазначена команда поверне:
No resources found.
Видаліть ConfigMap, Services та PersistentVolumeClaims.
kubectl delete configmap,service,pvc -l app=mysql
Якщо ви вручну створювали PersistentVolumes, вам також потрібно вручну видалити їх, а також звільнити відповідні ресурси. Якщо ви використовували динамічний провізор, він автоматично видаляє PersistentVolumes, коли бачить, що ви видалили PersistentVolumeClaims. Деякі динамічні провізори (такі як ті, що стосуються EBS та PD) також звільняють відповідні ресурси при видаленні PersistentVolumes.
Що далі
- Дізнайтеся більше про масштабування StatefulSet.
- Дізнайтеся більше про налагодження StatefulSet.
- Дізнайтеся більше про видалення StatefulSet.
- Дізнайтеся більше про примусове видалення Podʼів StatefulSet.
- Подивіться в сховищі Helm чартів інші приклади застосунків зі збереженням стану.
4 - Масштабування StatefulSet
Це завдання показує, як масштабувати StatefulSet. Масштабування StatefulSet означає збільшення або зменшення кількості реплік.
Перш ніж ви розпочнете
StatefulSets доступні тільки в версії Kubernetes 1.5 або пізніше. Щоб перевірити вашу версію Kubernetes, виконайте
kubectl version
.Не всі застосунки зі збереженням стану гарно масштабуються. Якщо ви не впевнені, чи масштабувати ваші StatefulSets, див. Концепції StatefulSet або Посібник StatefulSet для отримання додаткової інформації.
Ви повинні виконувати масштабування лише тоді, коли ви впевнені, що ваш кластер застосунку зі збереженням стану є повністю справним.
Масштабування StatefulSets
Використання kubectl для масштабування StatefulSets
Спочатку знайдіть StatefulSet, який ви хочете масштабувати.
kubectl get statefulsets <назва-stateful-set>
Змініть кількість реплік вашого StatefulSet:
kubectl scale statefulsets <назва-stateful-set> --replicas=<нові-репліки>
Виконання оновлень на місці для вашого StatefulSets
Альтернативно, ви можете виконати оновлення на місці для ваших StatefulSets.
Якщо ваш StatefulSet спочатку був створений за допомогою kubectl apply
, оновіть .spec.replicas
маніфестів StatefulSet, а потім виконайте kubectl apply
:
kubectl apply -f <stateful-set-file-updated>
Інакше, відредагуйте це поле за допомогою kubectl edit
:
kubectl edit statefulsets <stateful-set-name>
Або використовуйте kubectl patch
:
kubectl patch statefulsets <назва-stateful-set> -p '{"spec":{"replicas":<нові-репліки>}}'
Усунення несправностей
Масштабування вниз не працює правильно
Ви не можете зменшити масштаб StatefulSet, коли будь-який з Stateful Podʼів, яким він керує, є нездоровим. Масштабування відбувається лише після того, як ці Stateful Podʼи стають запущеними та готовими.
Якщо spec.replicas > 1, Kubernetes не може визначити причину несправності Podʼа. Це може бути наслідком постійного збою або тимчасового збою. Тимчасовий збій може бути викликаний перезапуском, необхідним для оновлення або обслуговування.
Якщо Pod несправний через постійний збій, масштабування без виправлення дефекту може призвести до стану, коли кількість членів StatefulSet опускається нижче певної мінімальної кількості реплік, необхідних для правильної роботи це може призвести до недоступності вашого StatefulSet.
Якщо Pod несправний через тимчасовий збій і Pod може стати доступним знову, тимчасова помилка може перешкоджати вашій операції масштабування вгору або вниз. Деякі розподілені бази даних мають проблеми, коли вузли приєднуються та відключаються одночасно. Краще розуміти операції масштабування на рівні застосунків у таких випадках і виконувати масштабування лише тоді, коли ви впевнені, що ваш кластер застосунку зі збереженням стану є цілком справним.
Що далі
- Дізнайтеся більше про видалення StatefulSet.
5 - Видалення StatefulSet
Це завдання показує, як видалити StatefulSet.
Перш ніж ви розпочнете
- Це завдання передбачає, що у вас є застосунок, який працює на вашому кластері та представлений StatefulSet.
Видалення StatefulSet
Ви можете видалити StatefulSet так само як і інші ресурси в Kubernetes: використовуйте команду kubectl delete
та вкажіть StatefulSet або файлом, або імʼям.
kubectl delete -f <file.yaml>
kubectl delete statefulsets <statefulset-name>
Після видалення StatefulSet може знадобитися окремо видалити повʼязаний headless service.
kubectl delete service <імʼя-сервісу>
Під час видалення StatefulSet через kubectl
, StatefulSet масштабується до 0. Всі Podʼи, які є частиною цього робочого навантаження, також видаляються. Якщо ви хочете видалити лише StatefulSet і не Podʼи, використовуйте --cascade=orphan
. Наприклад:
kubectl delete -f <файл.yaml> --cascade=orphan
Передачею --cascade=orphan
до kubectl delete
Podʼи, що керуються StatefulSet залишаються після того, як обʼєкт StatefulSet сам по собі буде видалений. Якщо Podʼи мають мітку app.kubernetes.io/name=MyApp
, ви можете видалити їх наступним чином:
kubectl delete pods -l app.kubernetes.io/name=MyApp
Постійні томи
Видалення Podʼів у StatefulSet не призведе до видалення повʼязаних томів. Це зроблено для того, щоб ви мали можливість скопіювати дані з тому перед його видаленням. Видалення PVC після завершення роботи Podʼів може спричинити видалення зазначених постійних томів залежно від класу сховища та політики повторного використання. Ніколи не припускайте можливість доступу до тому після видалення заявки.
Примітка:
Будьте обережні при видаленні PVC, оскільки це може призвести до втрати даних.Повне видалення StatefulSet
Щоб видалити все у StatefulSet, включаючи повʼязані Podʼи, ви можете виконати серію команд, схожих на наступні:
grace=$(kubectl get pods <под-stateful-set> --template '{{.spec.terminationGracePeriodSeconds}}')
kubectl delete statefulset -l app.kubernetes.io/name=MyApp
sleep $grace
kubectl delete pvc -l app.kubernetes.io/name=MyApp
У вище наведеному прикладі Podʼи мають мітку app.kubernetes.io/name=MyApp
; підставте вашу власну мітку за потреби.
Примусове видалення Podʼів StatefulSet
Якщо ви помітите, що деякі Podʼи у вашому StatefulSet застрягли у стані 'Terminating' або 'Unknown' протягом тривалого періоду часу, вам може знадобитися втрутитися вручну, щоб примусово видалити Podʼи з apiserverʼа. Це потенційно небезпечне завдання. Див. Примусове видалення Podʼів StatefulSet для отримання детальної інформації.
Що далі
Дізнайтеся більше про примусове видалення Podʼів StatefulSet.
6 - Примусове видалення Podʼів StatefulSet
Ця сторінка показує, як видаляти Podʼи, які є частиною StatefulSet, та пояснює важливі моменти, які слід враховувати під час цього.
Перш ніж ви розпочнете
- Це досить високорівневе завдання і може порушити деякі властивості, притаманні StatefulSet.
- Перед продовженням ознайомтеся з розглянутими нижче моментами.
Міркування про StatefulSet
При нормальному функціонуванні StatefulSet ніколи немає потреби у примусовому видаленні Podʼів StatefulSet. Контролер StatefulSet відповідає за створення, масштабування та видалення членів StatefulSet. Він намагається забезпечити, щоб зазначена кількість Podʼів від ordinal 0 до N-1 були справними та готовими. StatefulSet забезпечує те, що в будь-який момент часу в кластері працює не більше одного Podʼа з заданою ідентичністю. Це називається семантикою як максимум один, яку забезпечує StatefulSet.
Примусове видалення слід виконувати з обережністю, оскільки воно може порушити семантику "як максимум один", притаманну StatefulSet. StatefulSet можуть використовуватися для запуску розподілених і кластерних застосунків, які потребують стабільної мережевої ідентичності та стабільного сховища. Ці застосунки часто мають конфігурацію, яка ґрунтується на ансамблі фіксованої кількості членів з фіксованими ідентичностями. Наявність декількох членів із тією самою ідентичністю може бути руйнівною і може призвести до втрати даних (наприклад, у випадку "розщеплення мозку" в системах на основі кворуму).
Видалення Podʼів
Ви можете виконати коректне видалення Podʼа за допомогою наступної команди:
kubectl delete pods <pod>
Щоб таке видалення призвело до коректного завершення, необхідно вказати pod.Spec.TerminationGracePeriodSeconds
більше 0. Практика встановлення pod.Spec.TerminationGracePeriodSeconds
на 0 секунд є небезпечною та категорично не рекомендується для Podʼів StatefulSet. Коректне видалення є безпечним і забезпечить, що Pod коректно завершить роботу перед тим, як kubelet видалить імʼя з apiserver.
Pod не видаляється автоматично, коли вузол недоступний. Podʼи, які працюють на недоступному вузлі, потрапляють у стан 'Terminating' або 'Unknown' після тайм-ауту. Podʼи також можуть потрапляти в ці стани, коли користувач спробує коректне видалення Podʼа на недоступному вузлі. Єдині способи, якими Pod у такому стані може бути видалено з apiserver, наступні:
- Обʼєкт Node видаляється (або вами, або Контролером Вузлів).
- kubelet на недоступному Вузлі починає відповідати, припиняє роботу Pod та видаляє запис з apiserver.
- Примусове видалення Podʼа користувачем.
Рекомендована практика — використовувати перший або другий підхід. Якщо вузол підтверджено є несправним (наприклад, постійно відключений від мережі, вимкнений тощо), то видаліть обʼєкт Node. Якщо вузол страждає від розділення мережі, то спробуйте вирішити це або зачекайте на його вирішення. Коли розділення мережі виправляється, kubelet завершить видалення Podʼа та звільнить його імʼя в apiserver.
Зазвичай система завершує видалення, як тільки Pod більше не працює на Вузлі, або Вузол видаляється адміністратором. Ви можете перевизначити це за допомогою примусового видалення Podʼа.
Примусове видалення
Примусові видалення не чекають підтвердження від kubelet про те, що Pod було завершено. Незалежно від того, чи успішно примусове завершення Podʼа припиняє його роботу чи ні, воно негайно звільняє імʼя з apiserverʼа. Це дозволить контролеру StatefulSet створити новий Pod з тією самою ідентичністю; це може призвести до дублювання все ще працюючого Podʼа, і якщо цей Pod все ще може спілкуватися з іншими членами StatefulSet, це порушить семантику "як максимум один", яку StatefulSet має гарантувати.
Коли ви примусово видаляєте Pod StatefulSet, ви стверджуєте, що цей Pod більше ніколи не буде знову взаємодіяти з іншими Podʼами StatefulSet, і його імʼя може бути безпечно звільнено для створення заміни.
Якщо ви хочете примусово видалити Pod за допомогою kubectl версії >= 1.5, виконайте наступне:
kubectl delete pods <pod> --grace-period=0 --force
Якщо ви використовуєте будь-яку версію kubectl <= 1.4, ви повинні пропустити параметр --force
і використовувати:
kubectl delete pods <pod> --grace-period=0
Якщо навіть після цих команд Pod застряг у стані Unknown
, використайте наступну команду для видалення Podʼа з кластера:
kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
Завжди виконуйте примусове видалення Podʼів StatefulSet обережно та з повним розумінням ризиків, повʼязаних із цим.
Що далі
Дізнайтеся більше про налагодження StatefulSet.
7 - Горизонтальне автомасштабування Podʼів
У Kubernetes HorizontalPodAutoscaler автоматично оновлює ресурс навантаження (наприклад, Deployment або StatefulSet), з метою автоматичного масштабування робочого навантаження у відповідь на попит.
Горизонтальне масштабування означає, що реакція на збільшення навантаження полягає у розгортанні додаткових Podʼів. Це відрізняється від вертикального масштабування, що для Kubernetes означає призначення додаткових ресурсів (наприклад, памʼяті або CPU) для уже запущених Podʼів робочого навантаження.
Якщо навантаження зменшується, а кількість Podʼів перевищує налаштований мінімум, HorizontalPodAutoscaler інструктує ресурс навантаження (Deployment, StatefulSet або інший схожий ресурс) масштабуватися вниз.
Горизонтальне автоматичне масштабування Podʼів не застосовується до обʼєктів, які не можна масштабувати (наприклад, DaemonSet).
HorizontalPodAutoscaler реалізований як ресурс API Kubernetes та контролер. Ресурс визначає поведінку контролера. Контролер горизонтального автоматичного масштабування Podʼів, який працює в панелі управління Kubernetes, періодично коригує бажану шкалу своєї цілі (наприклад, Deployment), щоб відповідати спостережуваним метрикам, таким як середнє використання CPU, середня використання памʼяті або будь-яка інша метрика, яку ви вказуєте.
Ось приклад використання горизонтального автоматичного масштабування Podʼів.
Як працює HorizontalPodAutoscaler?
Схема 1. HorizontalPodAutoscaler керує масштабуванням Deployment та його ReplicaSet
У Kubernetes горизонтальне автоматичне масштабування Podʼів реалізовано як цикл керування, що працює інтервально (це не постійний процес). Інтервал встановлюється параметром --horizontal-pod-autoscaler-sync-period
для kube-controller-manager
(а стандартне значення — 15 секунд).
Один раз протягом кожного періоду менеджер контролера запитує використання ресурсів відповідно до метрик, вказаних у визначенні кожного HorizontalPodAutoscaler. Менеджер контролера знаходить цільовий ресурс, визначений за допомогою scaleTargetRef
, потім вибирає Podʼи на основі міток .spec.selector
цільового ресурсу та отримує метрики зі специфічних метрик ресурсів API (для метрик ресурсів на кожен Pod) або API власних метрик (для всіх інших метрик).
Для метрик ресурсів на кожен Pod (наприклад, CPU) контролер отримує метрики з API метрик ресурсів для кожного Pod, на який впливає HorizontalPodAutoscaler. Потім, якщо встановлено значення цільового використання, контролер обчислює значення використання як відсоток еквівалентного ресурсного запиту на контейнери в кожному Pod. Якщо встановлено сирцеве цільове значення, використовуються сирі (необроблені) значення метрик. Потім контролер бере середнє значення використання або сире значення (залежно від типу вказаної цілі) для всіх цільових Podʼів і створює співвідношення, яке використовується для масштабування кількості бажаних реплік.
Зверніть увагу, що якщо деякі контейнери Podʼів не мають відповідного ресурсного запиту, використання CPU для Pod не буде визначене, і автоматичний масштабувальник не буде виконувати жодних дій для цієї метрики. Дивіться розділ подробиці алгоритму нижче для отримання додаткової інформації про те, як працює алгоритм автомасштабування.
Для власних метрик на кожен Pod контролер працює аналогічно метрикам ресурсів на кожен Pod, за винятком того, що він працює з сирцевими значеннями, а не значеннями використання.
Для метрик обʼєктів та зовнішніх метрик витягується одна метрика, яка описує обʼєкт. Цю метрику порівнюють з цільовим значенням, щоб отримати співвідношення, як вище. У версії API
autoscaling/v2
це значення можна за необхідності розділити на кількість Podʼів до порівняння.
Звичайне використання HorizontalPodAutoscaler — налаштувати його на витягування метрик з агрегованих API (metrics.k8s.io
, custom.metrics.k8s.io
або external.metrics.k8s.io
). API metrics.k8s.io
зазвичай надається Metrics Server, який потрібно запустити окремо. Для отримання додаткової інформації про метрики ресурсів див. Metrics Server.
Підтримка API метрик пояснює гарантії стабільності та статус підтримки цих різних API.
Контролер HorizontalPodAutoscaler має доступ до відповідних ресурсів робочого навантаження, які підтримують масштабування (такі як Deployment та StatefulSet). Ці ресурси мають субресурс з назвою scale
, інтерфейс, який дозволяє динамічно встановлювати кількість реплік і переглядати поточний стан кожного з них. Для загальної інформації про субресурси в API Kubernetes див. Поняття API Kubernetes.
Алгоритм
По простому, контролер HorizontalPodAutoscaler працює зі співвідношенням між бажаним значенням метрики та поточним значенням метрики:
бажаніРепліки = ceil[поточніРепліки * ( поточнеЗначенняМетрики / бажанеЗначенняМетрики )]
Наприклад, якщо поточне значення метрики — 200м
, а бажане значення — 100м
, кількість реплік буде подвоєна, оскільки 200,0 / 100,0 == 2,0
. Якщо поточне значення замість цього — 50м
, кількість реплік буде зменшена вдвічі, оскільки 50,0 / 100,0 == 0,5
. Панель управління пропускає будь-яку дію масштабування, якщо співвідношення достатньо близьке до 1,0 (в межах глобально налаштованої допустимості, типово 0.1).
Якщо вказано targetAverageValue
або targetAverageUtilization
, поточне значення метрики обчислюється шляхом визначення середнього значення вказаної метрики для всіх Podʼів у цільовому масштабі HorizontalPodAutoscaler.
Перед перевіркою допустимості та визначенням кінцевих значень панель управління також розглядає, чи є відсутні будь-які метрики, і скільки Podʼів є Ready
. Всі Podʼи зі встановленим відбитками часу видалення (обʼєкти з відбитками часу видалення перебувають у процесі завершення роботи/видалення) ігноруються, а всі збійні Podʼи не враховуються.
Якщо конкретний Pod не маж метрики, його відкладено на потім; Podʼи з відсутніми метриками будуть використані для коригування кінцевої кількості масштабування.
При масштабуванні за CPU, якщо будь-який pod ще не став готовим (він все ще ініціалізується, або можливо, несправний) або остання точка метрики для Pod була до того, як він став готовим, цей Pod також відкладено.
Через технічні обмеження, контролер HorizontalPodAutoscaler не може точно визначити перший раз, коли Pod стає готовим при визначенні, чи відкласти певні метрики CPU. Замість цього вважається, що Pod "ще не готовий", якщо він ще не готовий і перейшов у готовий стан протягом короткого, налаштованого вікна часу з моменту початку. Це значення налаштоване за допомогою прапорця --horizontal-pod-autoscaler-initial-readiness-delay
, і типово воно складає 30 секунд. Як тільки Pod став готовим, будь-який перехід в готовий стан вважається першим, якщо це сталося протягом довшого, налаштованого часу від початку. Це значення налаштоване за допомогою прапорця
--horizontal-pod-autoscaler-cpu-initialization-period
, і його стандартне значення — 5 хвилин.
Базове співвідношення масштабу currentMetricValue / desiredMetricValue
потім обчислюється залишковими Podʼами, які не були відкладені або відкинуті вище.
Якщо були відсутні метрики, панель управління перераховує середнє значення більш консервативно, припускаючи, що ці Podʼи споживають 100% бажаного значення у випадку масштабування вниз і 0% у випадку масштабування вгору. Це зменшує величину можливого масштабу.
Крім того, якщо присутні будь-які ще не готові Podʼи, і робоче навантаження мало б масштабуватися вгору без врахування відсутніх метрик або ще не готових Podʼів, контролер консервативно припускає, що ще не готові Podʼи споживають 0% бажаної метрики, зменшуючи величини масштабу.
Після врахування ще не готових Podʼів та відсутніх метрик контролер повторно обчислює відношення використання. Якщо нове співвідношення змінює напрямок масштабування або знаходиться в межах допустимості, контролер не вживає жодних дій щодо масштабування. У інших випадках нове співвідношення використовується для прийняття будь-яких змін кількості Podʼів.
Зверніть увагу, що початкове значення для середнього використання повертається через статус HorizontalPodAutoscaler, без врахування ще не готових Podʼів або відсутніх метрик, навіть коли використовується нове відношення використання.
Якщо в HorizontalPodAutoscaler вказано кілька метрик, цей розрахунок виконується для кожної метрики, а потім обирається найбільше з бажаних кількостей реплік. Якщо будь-яка з цих метрик не може бути переведена у бажану кількість реплік (наприклад, через помилку отримання метрик з API метрик) і запропоновано масштабування вниз за метриками, які можна витягнути, масштабування пропускається. Це означає, що HPA все ще може масштабуватися вгору, якщо одна або декілька метрик дають значення desiredReplicas
, більше, ніж поточне значення.
Нарешті, прямо перед тим, як HPA масштабує ціль, рекомендація масштабування записується. Контролер розглядає всі рекомендації в налаштованому вікні та обирає найвищу рекомендацію в межах цього вікна. Це значення можна налаштувати за допомогою прапорця --horizontal-pod-autoscaler-downscale-stabilization
, який стандартно складає 5 хвилин. Це означає, що зменшення масштабу відбуватиметься поступово, згладжуючи вплив метрик, що швидко змінюються.
Обʼєкт API
Horizontal Pod Autoscaler є ресурсом API в групі API Kubernetes autoscaling
. Поточна стабільна версія знаходиться в версії API autoscaling/v2
, яка включає підтримку масштабування за памʼяттю та власними метриками. Нові поля, введені в autoscaling/v2
, зберігаються як анотації при роботі з autoscaling/v1
.
При створенні обʼєкта API HorizontalPodAutoscaler переконайтеся, що вказане імʼя є дійсним піддоменом DNS. Більше деталей про обʼєкт API можна знайти на сторінці Обʼєкт HorizontalPodAutoscaler.
Стабільність масштабування робочого навантаження
При керуванні масштабом групи реплік за допомогою HorizontalPodAutoscaler можливі часті коливання кількості реплік через динамічний характер оцінюваних метрик. Це іноді називають коливанням, або flapping. Це схоже на концепцію гістерезису в кібернетиці.
Масштабування під час поступового оновлення
Kubernetes дозволяє виконувати поступове оновлення для Deployment. У цьому випадку Deployment керує підлеглими ReplicaSets за вас. Коли ви налаштовуєте автомасштабування для Deployment, ви звʼязуєте HorizontalPodAutoscaler з одним Deployment. HorizontalPodAutoscaler керує полем replicas
Deployment. Контролер розгортання відповідає за встановлення replicas
підлеглих ReplicaSets так, щоб вони складали відповідну кількість під час розгортання, а також після його завершення.
Якщо ви виконуєте поступове оновлення StatefulSet, у якого є автомасштабована кількість реплік, StatefulSet безпосередньо керує своїм набором Podʼів (немає проміжного ресурсу, аналогічного ReplicaSet).
Підтримка метрик ресурсів
Будь-який обʼєкт HPA може бути масштабований на основі використання ресурсів у Podʼах цільового масштабування. При визначенні специфікації Podʼа повинні бути вказані запити ресурсів, такі як cpu
та memory
. Це використовується для визначення використання ресурсів і використовується контролером HPA для масштабування цілі вгору або вниз. Щоб використовувати масштабування на основі використання ресурсів, вкажіть джерело метрики так:
type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
З цією метрикою контролер HPA буде підтримувати середнє використання ресурсів у Podʼах цільового масштабування на рівні 60%. Використання — це співвідношення між поточним використанням ресурсу та запитаними ресурсами Podʼа. Дивіться Алгоритм для отримання додаткової інформації про те, як обчислюється та усереднюється використання.
Примітка:
Оскільки використання ресурсів всіх контейнерів сумується, загальне використання Podʼа може не точно відображати використання ресурсів окремих контейнерів. Це може призвести до ситуацій, коли один контейнер може працювати з високим використанням, а HPA не буде масштабувати його, оскільки загальне використання Podʼа все ще знаходиться в припустимих межах.Метрики ресурсів контейнера
Kubernetes v1.30 [stable]
(стандартно увімкнено: true)API HorizontalPodAutoscaler також підтримує джерело метрик контейнера, де HPA може відстежувати використання ресурсів окремих контейнерів у наборі Podʼів, щоб масштабувати цільовий ресурс. Це дозволяє налаштовувати пороги масштабування для контейнерів, які мають найбільше значення в конкретному Pod. Наприклад, якщо у вас є вебзастосунок і контейнер допоміжного сервісу (sidecar), який надає логування, ви можете масштабувати на основі використання ресурсів вебзастосунка, ігноруючи контейнер допоміжного сервісу (sidecar) та його використання ресурсів.
Якщо ви переглянете цільовий ресурс, щоб мати нову специфікацію Pod з іншим набором контейнерів, ви повинні відредагувати специфікацію HPA, якщо цей ново доданий контейнер також має бути використаний для масштабування. Якщо вказаний контейнер у джерелі метрики відсутній або присутній лише в підмножині Podʼів, то ці Podʼи ігноруються, і рекомендація перераховується. Дивіться Алгоритм для отримання додаткової інформації про обчислення. Щоб використовувати ресурси контейнера для автомасштабування, визначте джерело метрики таким чином:
type: ContainerResource
containerResource:
name: cpu
container: application
target:
type: Utilization
averageUtilization: 60
У вищенаведеному прикладі контролер HPA масштабує ціль так, що середнє використання cpu у контейнері application
у всіх подах становить 60%.
Примітка:
Якщо ви зміните імʼя контейнера, який відстежує HorizontalPodAutoscaler, ви можете зробити цю зміну у певному порядку, щоб забезпечити доступність та ефективність масштабування під час застосування змін. Перед тим, як ви оновите ресурс, який визначає контейнер (наприклад, Deployment), вам слід оновити повʼязаний HPA, щоб відстежувати як нові, так і старі імена контейнерів. Таким чином, HPA може розраховувати рекомендацію масштабування протягом усього процесу оновлення.
Після того, як ви розгорнули зміну імені контейнера на ресурсі навантаження, закінчіть, видаливши старе імʼя контейнера з характеристик HPA.
Масштабування на основі власних метрик
Kubernetes v1.23 [stable]
(версія API autoscaling/v2beta2
раніше надавала цю можливість як бета-функцію)
За умови використання версії API autoscaling/v2
ви можете налаштувати HorizontalPodAutoscaler на масштабування на основі власної метрики (яка не є вбудованою в Kubernetes або будь-який компонент Kubernetes). Потім контролер HorizontalPodAutoscaler запитує ці власні метрики з Kubernetes API.
Дивіться Підтримка API метрик для вимог.
Масштабування на основі декількох метрик
Kubernetes v1.23 [stable]
(версія API autoscaling/v2beta2
раніше надавала цю можливість як бета-функцію)
За умови використання версії API autoscaling/v2
ви можете вказати декілька метрик для HorizontalPodAutoscaler для масштабування на їх основі. Потім контролер HorizontalPodAutoscaler оцінює кожну метрику і пропонує новий масштаб на основі цієї метрики. HorizontalPodAutoscaler бере максимальний масштаб, рекомендований для кожної метрики, і встановлює робоче навантаження на такий розмір (за умови, що це не більше загального максимуму, який ви налаштували).
Підтримка API метрик
Стандартно контролер HorizontalPodAutoscaler отримує метрики з низки API. Для того щоб мати доступ до цих API, адміністратори кластера повинні забезпечити:
Увімкнути шар агрегації API.
Відповідні API мають бути зареєстровані:
Для метрик ресурсі це
metrics.k8s.io
API, яке зазвичай надає metrics-server. Це може бути запущено як надбудова кластера.Для власних метрик це
custom.metrics.k8s.io
API. Його надають сервери API "адаптера", які надають постачальники рішень метрик. Перевірте у своєї системи метрик, чи доступний адаптер метрик Kubernetes.Для зовнішніх метрик це
external.metrics.k8s.io
API. Він може бути наданий адаптерами власних метрик, які наведено вище.
Для отримання додаткової інформації про ці різні шляхи метрик та їх відмінності дивіться відповідні пропозиції дизайну для HPA V2, custom.metrics.k8s.io та external.metrics.k8s.io.
Для прикладів використання дивіться посібник з використання власних метрик та посібник з використання зовнішніх метрик.
Налаштований механізм масштабування
Kubernetes v1.23 [stable]
(версія API autoscaling/v2beta2
раніше надавала цю можливість як бета-функцію)
Якщо ви використовуєте API HorizontalPodAutoscaler v2
, ви можете використовувати поле behavior
(див. довідку API) для налаштування окремих поведінок масштабування вгору та вниз. Ви вказуєте ці поведінки, встановлюючи scaleUp
та/або scaleDown
у полі behavior
.
Ви можете вказати вікно стабілізації, яке запобігає коливанню кількості реплік для цільового масштабування. Політики масштабування також дозволяють контролювати швидкість зміни реплік під час масштабування.
Політики масштабування
Одну або декілька політик масштабування можна вказати у розділі behavior
специфікації. Коли вказано кілька політик, політика, яка дозволяє найбільше змін, є політикою, яка типово вибирається. Наступний приклад показує цю поведінку під час зменшення масштабу:
behavior:
scaleDown:
policies:
- type: Pods
value: 4
periodSeconds: 60
- type: Percent
value: 10
periodSeconds: 60
periodSeconds
вказує на проміжок часу в минулому, протягом якого політика має бути істинною. Максимальне значення, яке можна встановити для periodSeconds
, — 1800 (пів години). Перша політика (Pods) дозволяє зменшення максимум до 4 репліки протягом однієї хвилини. Друга політика (Percent) дозволяє зменшити максимум 10% поточних реплік протягом однієї хвилини.
Оскільки стандартно вибирається політика, яка дозволяє найбільше змін, друга політика буде використовуватися лише тоді, коли кількість реплік буде більше ніж 40. З 40 або менше реплік, буде застосована перша політика. Наприклад, якщо є 80 реплік, і ціль — зменшити масштаб до 10 реплік тоді під час першого кроку буде скорочено 8 реплік. На наступній ітерації, коли кількість реплік становить 72, 10% від реплік — 7,2, але число заокруглюється вгору до 8. На кожному кроці контролера автомасштабування перераховується кількість реплік, які мають бути змінені, на основі кількості поточних реплік. Коли кількість реплік падає нижче 40, застосовується перша політика (Pods) і зменшується по 4 репліки за раз.
Вибір політики можна змінити, вказавши поле selectPolicy
для напрямку масштабування. Встановлення значення Min
вибере політику, яка дозволяє найменшу зміну кількості реплік. Встановлення значення Disabled
повністю вимикає масштабування в даному напрямку.
Вікно стабілізації
Вікно стабілізації використовується для обмеження перепадів кількості реплік, коли метрики, які використовуються для масштабування, постійно коливаються. Алгоритм автоматичного масштабування використовує це вікно, щоб виявити попередній бажаний стан та уникнути непотрібних змін у масштабі навантаження.
Наприклад, у наступному виразі фрагменту коду вказано вікно стабілізації для scaleDown
.
behavior:
scaleDown:
stabilizationWindowSeconds: 300
Коли метрики показують, що потрібно зменшити ціль, алгоритм дивиться на раніше розраховані бажані стани і використовує найвище значення з вказаного інтервалу. У вищезазначеному прикладі всі попередні бажані стани за останні 5 хвилин будуть враховані.
Це наближається до ковзного максимуму і уникає ситуації, коли алгоритм масштабування часто видаляє Podʼи лише для того, щоб викликати повторне створення еквівалентного Podʼа за мить.
Стандартна поведінка
Для використання власного масштабування не всі поля повинні бути вказані. Можна вказати лише значення, які потрібно налаштувати. Ці власні значення злиті зі стандартними значеннями. Стандартні значення відповідають існуючій поведінці в алгоритмі HPA.
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
Для зменшення масштабу вікно стабілізації становить 300 секунд (або значення параметра --horizontal-pod-autoscaler-downscale-stabilization
, якщо воно вказане). Є лише одна політика для зменшення масштабу, яка дозволяє видалити 100% поточно запущених реплік, що означає, що ціль масштабування може бути зменшена до мінімально допустимих реплік. Для збільшення масштабу вікно стабілізації відсутнє. Коли метрики показують, що ціль повинна бути збільшена, ціль збільшується негайно. Є 2 політики, за якими кожні 15 секунд можна додати не більше 4 Podʼів або 100% поточно запущених реплік до тих пір, поки HPA не досягне стабільного стану.
Приклад: зміна вікна стабілізації для зменшення масштабу
Щоб вказати власне значення вікна стабілізації для зменшення масштабу тривалістю в 1 хвилину, в HPA буде додано наступну поведінку:
behavior:
scaleDown:
stabilizationWindowSeconds: 60
Приклад: обмеження коєфіцієнту зменшення масштабу
Щоб обмежити коєфіцієнт, з яким Podʼи видаляються HPA, до 10% за хвилину, до HPA додається наступна поведінка:
behavior:
scaleDown:
policies:
- type: Percent
value: 10
periodSeconds: 60
Щоб переконатися, що за хвилину видаляється не більше 5 Podʼів, можна додати другу політику зменшення масштабу з фіксованим розміром 5 та встановити selectPolicy
на значення Min
. Встановлення selectPolicy
на Min
означає, що автомасштабувальник вибирає політику, яка впливає на найменшу кількість Podʼів:
behavior:
scaleDown:
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 5
periodSeconds: 60
selectPolicy: Min
Приклад: вимкнення зменшення масштабу
Значення selectPolicy
Disabled
вимикає масштабування вказаного напрямку. Щоб запобігти зменшенню масштабу, буде використана наступна політика:
behavior:
scaleDown:
selectPolicy: Disabled
Підтримка HorizontalPodAutoscaler в kubectl
HorizontalPodAutoscaler, як і кожний ресурс API, підтримується стандартним чином у kubectl
. Ви можете створити новий автомасштабувальник за допомогою команди kubectl create
. Ви можете переглянути список автомасштабувальників за допомогою kubectl get hpa
або отримати детальний опис за допомогою kubectl describe hpa
. Нарешті, ви можете видалити автомасштабувальник за допомогою kubectl delete hpa
.
Крім того, є спеціальна команда kubectl autoscale
для створення обʼєкта HorizontalPodAutoscaler. Наприклад, виконання kubectl autoscale rs foo --min=2 --max=5 --cpu-percent=80
створить автомасштабувальник для ReplicaSet foo, з цільовим використанням процесора, встановленим на 80%
і кількістю реплік від 2 до 5.
Неявне деактивування режиму підтримки
Ви можете неявно деактивувати HPA для цільового обʼєкта без необхідності змінювати конфігурацію HPA самостійно. Якщо бажана кількість реплік цільового обʼєкта встановлена на 0, а мінімальна кількість реплік HPA більше 0, HPA припиняє коригування цільового обʼєкта (і встановлює умову ScalingActive
на собі в false
) до тих пір, поки ви не активуєте його вручну, змінивши бажану кількість реплік цільового обʼєкта або мінімальну кількість реплік HPA.
Перехід Deployment та StatefulSet на горизонтальне масштабування
При увімкненні HPA рекомендується видалити значення spec.replicas
з Deployment та/або StatefulSet в їхніх маніфестах. Якщо цього не зроблено, будь-яка зміна в цьому обʼєкті, наприклад за допомогою kubectl apply -f deployment.yaml
, буде інструкцією Kubernetes масштабувати поточну кількість Podʼів до значення ключа spec.replicas
. Це може бути небажаним і призводити до проблем, коли HPA активно працює.
Майте на увазі, що видалення spec.replicas
може спричинити одноразове зниження кількості Podʼів, оскільки стандартне значення цього ключа — 1 (див. Репліки Deployment). Після оновлення всі Podʼи, крім одного, розпочнуть процедури їхнього завершення. Після цього будь-яке подальше розгортання застосунку буде працювати як звичайно і буде дотримуватися конфігурації плавного оновлення за бажанням. Ви можете уникнути цього зниження, обравши один із двох наступних методів в залежності від того, як ви модифікуєте свої розгортання:
kubectl apply edit-last-applied deployment/<deployment_name>
- У редакторі видаліть
spec.replicas
. Після збереження та виходу з редактора,kubectl
застосовує оновлення. На цьому етапі не відбувається змін кількості Podʼів. - Тепер ви можете видалити
spec.replicas
з маніфеста. Якщо ви використовуєте систему управління вихідним кодом, також зафіксуйте ваші зміни або виконайте будь-які інші кроки для перегляду вихідного коду, які відповідають вашому способу відстеження оновлень. - Відтепер ви можете запускати
kubectl apply -f deployment.yaml
При використанні Server-Side Apply ви можете дотримуватися вказівок щодо передачі власності, які охоплюють цей саме випадок використання.
Що далі
Якщо ви налаштовуєте автомасштабування у вашому кластері, вам також може бути корисно розглянути використання автомасштабування кластера для забезпечення того, що ви запускаєте правильну кількість вузлів.
Для отримання додаткової інформації про HorizontalPodAutoscaler:
- Прочитайте приклад для автоматичного горизонтального масштабування Podʼів.
- Прочитайте документацію для
kubectl autoscale
. - Якщо ви бажаєте написати власний адаптер для власних метрик, перегляньте початковий код, щоб почати.
- Ознайомтесь з Довідкою API для HorizontalPodAutoscaler.
8 - Покрокове керівництво HorizontalPodAutoscaler
HorizontalPodAutoscaler (HPA) автоматично оновлює ресурс робочого навантаження (наприклад, Deployment або StatefulSet), з метою автоматичного масштабування робочого навантаження, щоб відповідати попиту.
Горизонтальне масштабування означає, що відповідь на збільшене навантаження полягає в розгортанні додаткових Podʼів. Це відрізняється від вертикального масштабування, що для Kubernetes означає призначення додаткових ресурсів (наприклад: памʼять або CPU) для Podʼів, які вже працюють для робочого навантаження.
Якщо навантаження зменшується, а кількість Podʼів перевищує налаштований мінімум, HorizontalPodAutoscaler інструктує ресурс робочого навантаження (Deployment, StatefulSet або інший схожий ресурс) зменшити масштаб.
Цей документ детально розглядає приклад увімкнення HorizontalPodAutoscaler для автоматичного управління масштабуванням для прикладу вебзастосунку. Це приклад навантаження — Apache httpd, що виконує деякий код PHP.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж 1.23. Для перевірки версії введітьkubectl version
.
Якщо ви використовуєте старі версії Kubernetes, зверніться до документації для цієї версії (див. доступні версії документації).Для виконання рекомендацій цього посібника, вам також потрібно використовувати кластер, в якому розгорнутий і налаштований Metrics Server. Сервер метрик Kubernetes збирає метрики ресурсів з kubelets у вашому кластері та використовує ці метрики через Kubernetes API, використовуючи APIService, щоб додати нові види ресурсів, які представляють метричні показники.
Щоб дізнатися, як розгорнути Metrics Server, див. документацію metrics-server.
Якщо ви використовуєте Minikube, виконайте наступну команду для ввімкнення metrics-server:
minikube addons enable metrics-server
Запустіть та надайте доступ до сервера php-apache
Для демонстрації HorizontalPodAutoscaler ви спочатку запустите Deployment, який запускає контейнер за допомогою образу hpa-example
, та експонуєте його як Service за допомогою наступного маніфесту:
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
Для цього виконайте наступну команду:
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache створено
service/php-apache створено
Створіть HorizontalPodAutoscaler
Тепер, коли сервер працює, створіть автомасштабувальник за допомогою kubectl
. Підкоманда kubectl autoscale
, частина kubectl
, допоможе зробити це.
За мить ви виконаєте команду, яка створить HorizontalPodAutoscaler, що підтримує від 1 до 10 реплік контрольованих Podʼів за допомогою Deployment php-apache, який ви створили на першому етапі цих інструкцій.
Грубо кажучи, контролер контролер HPA збільшує або зменшує кількість реплік (шляхом оновлення Deployment) для підтримки середнього використання процесора на рівні 50% по всіх Podʼах. Deployment потім оновлює ReplicaSet — це частина всіх Deployment у Kubernetes — і потім ReplicaSet додає або видаляє Podʼи на основі змін у його .spec
.
Оскільки кожен Pod запитує 200 мілі-ядер за допомогою kubectl run
, це означає середнє використання процесора 100 мілі-ядер. Див. Деталі алгоритму для отримання додаткової інформації щодо алгоритму.
Створіть HorizontalPodAutoscaler:
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache масштабовано
Ви можете перевірити поточний стан нового HorizontalPodAutoscaler, виконавши:
# Ви можете використовувати "hpa" або "horizontalpodautoscaler"; обидва імені працюють добре.
kubectl get hpa
Вивід схожий на:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 18s
(якщо ви бачите інші HorizontalPodAutoscalers з різними іменами, це означає, що вони вже існували, і це зазвичай не проблема).
Зверніть увагу, що поточне використання ЦП становить 0%, оскільки немає клієнтів, що відправляють запити на сервер (стовпець «TARGET» показує середнє значення по всіх Podʼах, що контролюються відповідним розгортанням).
Збільшення навантаження
Далі перегляньте, як автомасштабувальник реагує на збільшене навантаження. Для цього ви запустите інший Pod, який буде виступати в ролі клієнта. Контейнер всередині Podʼа клієнта працює у нескінченному циклі, надсилаючи запити до служби php-apache.
# Виконайте це в окремому терміналі,
# щоб навантаження продовжувалося, і ви могли продовжити роботу з рештою кроків
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
Тепер виконайте:
# натисніть Ctrl+C, щоб припинити перегляд, коли будете готові
kubectl get hpa php-apache --watch
Протягом хвилини ви повинні побачити вище навантаження процесора; наприклад:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 1 3m
а потім більше реплік. Наприклад:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 305% / 50% 1 10 7 3m
Тут споживання ЦП збільшилося до 305% від запиту. В результаті Deployment був змінений до 7 реплік:
kubectl get deployment php-apache
Ви повинні побачити, що кількість реплік відповідає цифрі з HorizontalPodAutoscaler
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 7/7 7 7 19m
Примітка:
Може знадобитися кілька хвилин, щоб стабілізувалася кількість реплік. Оскільки обсяг навантаження не контролюється, може статися так, що кінцева кількість реплік буде відрізнятися від цього прикладу.Зупиніть генерування навантаження
Для завершення прикладу припиніть надсилання навантаження.
У терміналі, де ви створили Pod, який працює з образом busybox
, зупиніть генерування навантаження, натиснувши <Ctrl> + C
.
Потім перевірте результат (через хвилину чи так):
# натисніть Ctrl+C, щоб припинити перегляд, коли будете готові
kubectl get hpa php-apache --watch
Вивід схожий на:
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache/scale 0% / 50% 1 10 1 11m
і Deployment також показує, що він зменшився:
kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 27m
Як тільки використання CPU знизилося до 0, HPA автоматично зменшив кількість реплік до 1.
Автоматичне масштабування реплік може зайняти кілька хвилин.
Автомасштабування за допомогою кількох метрик та власних метрик
Ви можете вводити додаткові метрики для використання при автомасштабуванні Deployment php-apache
, використовуючи версію API autoscaling/v2
.
Спочатку отримайте YAML вашого HorizontalPodAutoscaler у формі autoscaling/v2
:
kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml
Відкрийте файл /tmp/hpa-v2.yaml
у редакторі, і ви побачите YAML, що виглядає наступним чином:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
Зверніть увагу, що поле targetCPUUtilizationPercentage
було замінено масивом під назвою metrics
. Метрика використання ЦП є ресурсною метрикою, оскільки вона представлена як відсоток ресурсу, вказаного в контейнерах Podʼа. Зверніть увагу, що ви можете вказати інші ресурсні метрики крім ЦП. Стандартно, єдиним іншим підтримуваним типом ресурсної метрики є memory
. Ці ресурси не змінюють назви з кластера на кластер і завжди повинні бути доступними, поки API metrics.k8s.io
доступне.
Ви також можете вказати ресурсні метрики у вигляді безпосередніх значень, а не як відсотки від запитаного значення, використовуючи target.type
AverageValue
замість Utilization
, і встановлюючи відповідне поле target.averageValue
замість target.averageUtilization
.
metrics:
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 500Mi
Є ще два інші типи метрик, які обидва вважаються власними метриками: метрики Podʼів і метрики обʼєктів. Ці метрики можуть мати назви, які специфічні для кластера, і вимагають більш розширеної настройки моніторингу кластера.
Перший з цих альтернативних типів метрик — це метрики Podʼів. Ці метрики описують Podʼи і вони усереднюються разом по Podʼах і порівнюються з цільовим значенням для визначення кількості реплік. Вони працюють так само як ресурсні метрики, за винятком того, що вони тільки підтримують тип target
AverageValue
.
Метрики Podʼів вказуються за допомогою блоку метрики, подібного до цього:
type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
Другий альтернативний тип метрики — це метрики обʼєктів. Ці метрики описують інший обʼєкт в тому ж просторі імен, замість опису Podʼів. Метрики не обовʼязково отримуються з обʼєкта; вони лише описують його. Метрики обʼєктів підтримують типи target
як Value
і AverageValue
. З Value
ціль порівнюється безпосередньо з метрикою отриманою з API. З AverageValue
значення, повернене з API власних метрик, ділиться на кількість Podʼів перед порівнянням з цільовим значенням. Ось приклад YAML представлення метрики requests-per-second
.
type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
target:
type: Value
value: 2k
Якщо ви надаєте кілька таких блоків метрик, HorizontalPodAutoscaler буде розглядати кожну метрику по черзі. HorizontalPodAutoscaler розраховуватиме запропоновані кількості реплік для кожної метрики, а потім вибере той, який має найбільшу кількість реплік.
Наприклад, якщо ваша система моніторингу збирає метрики про мережевий трафік, ви можете оновити визначення вище за допомогою kubectl edit
так, щоб воно виглядало наступним чином:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
status:
observedGeneration: 1
lastScaleTime: <some-time>
currentReplicas: 1
desiredReplicas: 1
currentMetrics:
- type: Resource
resource:
name: cpu
current:
averageUtilization: 0
averageValue: 0
- type: Object
object:
metric:
name: requests-per-second
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: main-route
current:
value: 10k
Тоді ваш HorizontalPodAutoscaler намагатиметься забезпечити, щоб кожен Pod витрачав приблизно 50% від своєї запитаної CPU, обслуговував 1000 пакетів за секунду та всі Podʼи за головним маршрутом Ingress обслуговували в загальному 10000 запитів за секунду.
Автомасштабування за більш конкретними метриками
Багато систем метрик дозволяють описувати метрики або за назвою, або за набором додаткових описів, які називаються мітками (labels). Для всіх типів метрик, крім ресурсних (Podʼів, обʼєктів і зовнішніх, описаних нижче), ви можете вказати додатковий селектор міток, який передається вашій системі метрик. Наприклад, якщо ви збираєте метрику http_requests
з міткою verb
, ви можете вказати наступний блок метрики, щоб масштабувати тільки на запити GET:
type: Object
object:
metric:
name: http_requests
selector: {matchLabels: {verb: GET}}
Цей селектор використовує такий же синтаксис, як і повні селектори міток Kubernetes. Система моніторингу визначає, як зведені кілька серій в одне значення, якщо імʼя та селектор відповідають кільком серіям. Селектор є додатковим, і не може вибирати метрики, що описують обʼєкти, які не є цільовим обʼєктом (цільові Podʼи у випадку типу Pods
, та описаний обʼєкт у випадку типу Object
).
Автомасштабування за метриками, що не стосуються обʼєктів Kubernetes
Застосунки, які працюють на Kubernetes, можуть потребувати автоматичного масштабування на основі метрик, які не мають очевидного стосунку до будь-якого обʼєкта в кластері Kubernetes, наприклад, метрики, що описують хостову службу з жодною прямою кореляцією з просторами імен Kubernetes. У Kubernetes 1.10 і пізніших версіях ви можете вирішити цей випадок використовуючи зовнішні метрики.
Для використання зовнішніх метрик потрібно знання вашої системи моніторингу; налаштування аналогічно необхідному при використанні власних метрик. Зовнішні метрики дозволяють автоматично масштабувати ваш кластер на основі будь-якої метрики, доступної в вашій системі моніторингу. Надайте блок metric
з name
та selector
, як вище, і використовуйте тип метрики External
замість Object
. Якщо кілька часових рядів відповідають metricSelector
, то сума їх значень використовується HorizontalPodAutoscaler. Зовнішні метрики підтримують як типи цілей Value
, так і AverageValue
, які працюють точно так само, як коли ви використовуєте тип Object
.
Наприклад, якщо ваш додаток обробляє завдання з хостової служби черги, ви можете додати наступний розділ до вашого маніфесту HorizontalPodAutoscaler, щоб вказати, що вам потрібен один робочий процес на кожні 30 невиконаних завдань.
- type: External
external:
metric:
name: queue_messages_ready
selector:
matchLabels:
queue: "worker_tasks"
target:
type: AverageValue
averageValue: 30
Коли це можливо, краще використовувати типи цілей власних метрик замість зовнішніх метрик, оскільки для адміністраторів кластера легше захистити API власних метрик. Зовнішнє API метрик потенційно дозволяє доступ до будь-якої метрики, тому адміністратори кластера повинні бути обережні при його використанні.
Додаток: Умови стану горизонтального автомасштабування Podʼів
При використанні форми autoscaling/v2
HorizontalPodAutoscaler ви зможете бачити умови стану, встановлені Kubernetes на HorizontalPodAutoscaler. Ці умови стану вказують, чи може або не може HorizontalPodAutoscaler масштабуватися, а також чи є в цей час будь-які обмеження.
Умови зʼявляються у полі status.conditions
. Щоб побачити умови, які впливають на HorizontalPodAutoscaler, ми можемо використати kubectl describe hpa
:
kubectl describe hpa cm-test
Name: cm-test
Namespace: prom
Labels: <none>
Annotations: <none>
CreationTimestamp: Fri, 16 Jun 2017 18:09:22 +0000
Reference: ReplicationController/cm-test
Metrics: ( current / target )
"http_requests" on pods: 66m / 500m
Min replicas: 1
Max replicas: 4
ReplicationController pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale the last scale time was sufficiently old as to warrant a new scale
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests
ScalingLimited False DesiredWithinRange the desired replica count is within the acceptable range
Events:
Для цього HorizontalPodAutoscaler ви можете побачити кілька умов у справному стані. Перше, AbleToScale
, вказує, чи може або не може HPA отримувати та оновлювати масштаби, а також чи будь-які умови затримки повʼязані з масштабуванням. Друге, ScalingActive
, вказує, чи увімкнений HPA (тобто кількість реплік цілі не дорівнює нулю) та чи може розраховувати потрібні масштаби. Якщо це False
, це, як правило, вказує на проблеми з отриманням метрик. Нарешті, остання умова, ScalingLimited
, вказує на те, що потрібний масштаб був обмежений максимальним або мінімальним значенням HorizontalPodAutoscaler. Це свідчить про те, що ви можливо захочете збільшити або зменшити мінімальну або максимальну кількість реплік на вашому HorizontalPodAutoscaler.
Кількості
Усі метрики в HorizontalPodAutoscaler та API метрик вказуються за спеціальною цільною числовою нотацією, відомою в Kubernetes як кількість. Наприклад, кількість 10500m
буде записана як 10.5
у десятковій нотації. API метрик повертатимуть цілі числа без суфікса, якщо це можливо, і зазвичай повертають кількості в міліодиницях у протилежному випадку. Це означає, що ви можете бачити зміну вашого значення метрики між 1
і 1500m
, або між 1
і 1.5
, коли воно записане в десятковій нотації.
Інші можливі сценарії
Створення автомасштабування декларативно
Замість використання команди kubectl autoscale
для створення HorizontalPodAutoscaler імперативно, ми можемо використати наступний маніфест, щоб створити його декларативно:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
Потім створіть автомасштабування, виконавши наступну команду:
kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created
9 - Вказання бюджету розладів для вашого застосунку
Kubernetes v1.21 [stable]
На цій сторінці показано, як обмежити кількість одночасних розладів, які очікує ваш застосунок, що дозволяє підвищити доступність і дозволяє адміністратору кластера управляти вузлами кластера.
Перш ніж ви розпочнете
Версія вашого Kubernetes сервера має бути не старішою ніж v1.21. Для перевірки версії введітьkubectl version
.- Ви є власником застосунку, який працює на кластері Kubernetes і вимагає високої доступності.
- Вам слід знати, як розгорнути репліковані застосунки без збереження стану та/або репліковані застосунки зі збереженням стану.
- Ви повинні прочитати про розлади Podʼів.
- Ви повинні підтвердити з власником кластера або постачальником послуг, що вони дотримуються Бюджетів розладів Podʼів.
Захист застосунку за допомогою PodDisruptionBudget
- Визначте, який застосунок ви хочете захистити за допомогою PodDisruptionBudget (PDB).
- Подумайте про те, як ваш застосунок реагує на розлади.
- Створіть визначення PDB у вигляді файлу YAML.
- Створіть обʼєкт PDB з файлу YAML.
Визначення застосунку для захисту
Найбільш поширене використання полягає в захисті застосунку, який визначено одним із вбудованих контролерів Kubernetes:
- Deployment (Розгортання)
- ReplicationController (Контролер Реплікації)
- ReplicaSet (Набір Реплік)
- StatefulSet (Набір зі Станом)
У цьому випадку обовʼязково відзначте .spec.selector
контролера; той самий селектор використовується в .spec.selector
PDBs.
Починаючи з версії 1.15, PDB підтримують власні контролери, де включено субресурс масштабування.
Також можна використовувати PDB зі сторонніми Podʼами, які не контролюються одним із вищевказаних контролерів, або з довільними групами Podʼів, але є деякі обмеження, описані у Довільні робочі навантаження та довільні селектори.
Подумайте про реакцію вашого застосунку на відключення
Вирішіть, скільки екземплярів може бути вимкнено одночасно на короткий період часу через добровільні відключення.
- Фронтенди без збереження стану:
- Застереження: не зменшуйте потужність обслуговування більш ніж на 10%.
- Рішення: використовуйте PDB з minAvailable 90%, наприклад.
- Застереження: не зменшуйте потужність обслуговування більш ніж на 10%.
- Одноекземплярний застосунок зі збереженням стану:
- Застереження: не закривайте цей застосунок без спілкування зі мною.
- Можливе рішення 1: Не використовуйте PDB і терпіть випадковий простій.
- Можливе рішення 2: Встановіть PDB з maxUnavailable=0. Маючи розуміння (поза Kubernetes), що оператор кластера повинен звʼязатися з вами перед закриттям. Коли оператор кластера звертається до вас, готуйтеся до простою, а потім видаліть PDB, щоб показати готовність до відключення. Після цього створіть новий.
- Застереження: не закривайте цей застосунок без спілкування зі мною.
- Багатоекземплярний застосунок зі збереженням стану, такий як Consul, ZooKeeper або etcd:
- Застереження: не зменшуйте кількість екземплярів нижче кворуму, в іншому випадку записи будуть невдалі.
- Можливе рішення 1: встановіть maxUnavailable на рівень 1 (працює з різними масштабами застосунку).
- Можливе рішення 2: встановіть minAvailable рівним розміру кворуму (наприклад, 3 при масштабуванні 5). (Дозволяє більше відключень одночасно).
- Застереження: не зменшуйте кількість екземплярів нижче кворуму, в іншому випадку записи будуть невдалі.
- Пакетне завдання (Job) з перезапуском:
- Застереження: завдання повинно завершитися у разі добровільного відключення.
- Можливе рішення: Не створюйте PDB. Контролер завдань створить Pod на заміну.
- Застереження: завдання повинно завершитися у разі добровільного відключення.
Логіка округлення при вказанні відсотків
Значення для minAvailable
або maxUnavailable
можуть бути виражені як цілі числа або як відсотки.
- Коли ви вказуєте ціле число, воно представляє кількість Podʼів. Наприклад, якщо ви встановите
minAvailable
на 10, то завжди повинно бути доступно 10 Podʼів, навіть під час відключення. - Коли ви вказуєте відсоток, встановивши значення як рядкове представлення відсотка (наприклад,
"50%"
), воно представляє відсоток від загальної кількості Podʼів. Наприклад, якщо ви встановитеminAvailable
на"50%"
, то принаймні 50% Podʼів залишаться доступними під час відключення.
Коли ви вказуєте значення як відсоток, це може не відповідати точній кількості Podʼів. Наприклад, якщо у вас є 7 Podʼів і ви встановите minAvailable
на "50%"
, то не зразу очевидно, чи має це означати, що повинно бути доступно 3 або 4 Podʼи. Kubernetes округлює до найближчого цілого числа, тому в цьому випадку повинно бути доступно 4 Podʼи. Коли ви вказуєте значення maxUnavailable
як відсоток, Kubernetes округлює кількість Podʼів, які можуть бути відключені. Таким чином, відключення може перевищувати ваш визначений відсоток maxUnavailable
. Ви можете ознайомитися з кодом,
який керує такою поведінкою.
Вказання PodDisruptionBudget
PodDisruptionBudget
має три поля:
- Селектор міток
.spec.selector
, щоб вказати набір Podʼів, до яких він застосовується. Це поле обовʼязкове. .spec.minAvailable
— це опис кількості Podʼів з цього набору, які повинні залишитися доступними після відключення, навіть у відсутності відключеного Podʼа.minAvailable
може бути абсолютним числом або відсотком..spec.maxUnavailable
(доступний у Kubernetes 1.7 та вище) — це опис кількості Podʼів з цього набору, які можуть бути недоступними після відключення. Це також може бути абсолютним числом або відсотком.
Примітка:
Поведінка для порожнього селектора відрізняється між policy/v1beta1 та policy/v1 API для PodDisruptionBudgets. Для policy/v1beta1 порожній селектор відповідає нулю Podʼів, тоді як для policy/v1 порожній селектор відповідає кожному Podʼа у просторі імен.Ви можете вказати лише один із maxUnavailable
або minAvailable
в одному PodDisruptionBudget
. maxUnavailable
може бути використаний лише для контролю відключення Podʼів, які мають повʼязаний контролер, який керує ними. У наведених нижче прикладах, "бажані репліки" — це масштаб контролера, що керує Podʼами, які вибрані PodDisruptionBudget
.
Приклад 1: З minAvailable
5, відключення дозволяються, поки залишаються 5 або більше справних Podʼів серед тих, які вибрані селектором PodDisruptionBudget.
Приклад 2: З minAvailable
30%, відключення дозволяються, якщо принаймні 30% від кількості бажаних реплік є справними.
Приклад 3: З maxUnavailable
5, відключення дозволяються, поки є не більше 5 несправних реплік серед загальної кількості бажаних реплік.
Приклад 4: З maxUnavailable
30%, відключення дозволяються, якщо кількість несправних реплік не перевищує 30% від загальної кількості бажаних реплік, округленої до найближчого цілого числа. Якщо загальна кількість бажаних реплік — лише одна, ця єдина репліка все ще допускається до відключення, що призводить до ефективної недоступності на 100%.
У типовому використанні один бюджет використовуватиметься для збірки Podʼів, керованих контролером — наприклад, Podʼів у одному ReplicaSet або StatefulSet.
Примітка:
Бюджет відключення фактично не гарантує, що вказана кількість/відсоток Podʼів завжди буде активними. Наприклад, вузол, на якому розміщено Pod зі збірки, може вийти з ладу, коли збірка досягне мінімального розміру, вказаного в бюджеті, що призведе до зменшення кількості доступних Podʼів зі збірки нижче вказаного розміру. Бюджет може захищати лише від добровільних виселень, а не від всіх причин недоступності.Якщо ви встановите maxUnavailable
на 0% або 0, або ви встановите minAvailable
на 100% або рівну кількості реплік, ви вимагаєте нульових добровільних виселень. Коли ви встановлюєте нульові добровільні відключення для робочого навантаження, такого як ReplicaSet, тоді ви не зможете успішно вивести з експлуатації вузол, на якому працює один з цих Podʼів. Якщо ви намагаєтеся вивести з експлуатації вузол, де працює невиселяємий Pod, відключення ніколи не завершиться. Це допускається згідно з семантикою PodDisruptionBudget
.
Ви можете знайти приклади визначення бюджетів відключення Podʼів нижче. Вони відповідають Podʼам з міткою app: zookeeper
.
Приклад PDB з використанням minAvailable
:
Приклад PDB з використанням maxUnavailable
:
Наприклад, якщо вищезгаданий обʼєкт zk-pdb
вибирає Podʼи з StatefulSet розміром 3, обидві
специфікації мають точно таке ж значення. Рекомендується використання maxUnavailable
, оскільки він автоматично реагує на зміни кількості реплік відповідного контролера.
Створення обʼєкта PodDisruptionBudget
Для створення або оновлення обʼєкта PDB використовуйте наступну команду kubectl
:
kubectl apply -f mypdb.yaml
Перевірка статусу обʼєкта PodDisruptionBudget
Щоб перевірити статус обʼєкта PDB, скористайтеся наступною командою kubectl
.
Якщо в вашому просторі імен відсутні Podʼи, що відповідають мітці app: zookeeper
, ви побачите щось подібне:
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 0 7s
Якщо є Podʼи, які відповідають умовам (скажімо, 3), то ви побачите щось на кшталт:
kubectl get poddisruptionbudgets
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zk-pdb 2 N/A 1 7s
Ненульове значення для ALLOWED DISRUPTIONS
означає, що контролер відключення Podʼів бачив Podʼи, підрахував відповідні Podʼи і оновив статус PDB.
Ви можете отримати більше інформації про статус PDB за допомогою цієї команди:
kubectl get poddisruptionbudgets zk-pdb -o yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
annotations:
…
creationTimestamp: "2020-03-04T04:22:56Z"
generation: 1
name: zk-pdb
…
status:
currentHealthy: 3
desiredHealthy: 2
disruptionsAllowed: 1
expectedPods: 3
observedGeneration: 1
Справність Pod
Поточна реалізація вважає Podʼи справними, якщо вони мають елемент .status.conditions
з type="Ready"
і status="True"
. Ці Podʼи відстежуються через поле .status.currentHealthy
в статусі PDB.
Політика виселення несправних Podʼів
Kubernetes v1.31 [stable]
(стандартно увімкнено: true)PodDisruptionBudget, який охороняє застосунок, забезпечує, що кількість Podʼів зі статусом .status.currentHealthy
не опуститься нижче, ніж кількість, вказана у .status.desiredHealthy
, не дозволяючи видалення справних Podʼів. Використовуючи .spec.unhealthyPodEvictionPolicy
, ви також можете визначити критерії, коли несправні Podʼи повинні розглядатися для видалення. Стандартна поведінка, коли політика не вказана, відповідає політиці IfHealthyBudget
.
Політики:
IfHealthyBudget
- Запущені Podʼи (
.status.phase="Running"
), але ще не справні, можуть бути виселені тільки якщо охоронюваний застосунок не відключений (.status.currentHealthy
щонайменше дорівнює.status.desiredHealthy
). Ця політика забезпечує, що запущені Podʼи вже відключеного застосунку мають кращі шанси стати справними. Це має негативні наслідки для виведення вузлів з експлуатації, які можуть бути заблоковані неправильно працюючими застосунками, які охороняються PDB. Зокрема, застосунки з Podʼами у стані
CrashLoopBackOff
(через помилку або неправильну конфігурацію), або Podʼи, яким просто не вдається повідомити умовуReady
.AlwaysAllow
- Запущені Podʼи (
.status.phase="Running"
), але ще не справні вважаються відключеними та можуть бути видалені незалежно від того, чи виконуються критерії в PDB. Це означає, що майбутні запущені Podʼи відключеного застосунку можуть не мати можливості стати справними. Використовуючи цю політику, менеджери кластера можуть легко вивести з експлуатації неправильно працюючі застосунки, які охороняються PDB. Зокрема, застосунки з Podʼами у стані
CrashLoopBackOff
(через помилку або неправильну конфігурацію), або Podʼи, які просто не вдаються відправити умовуReady
.
Примітка:
Podʼи у фазахPending
, Succeeded
або Failed
завжди вважаються кандидатами на виселення.Довільні робочі навантаження та селектори
Ви можете пропустити цей розділ, якщо ви використовуєте PDB лише зі вбудованими ресурсами навантаження (Deployment, ReplicaSet, StatefulSet та ReplicationController) або з власними ресурсами, які реалізують субресурс scale
, і де селектор PDB точно відповідає селектору власного ресурсу Podʼа.
Ви можете використовувати PDB з підпроцесами, керованими іншим ресурсом, "оператором" або голими підпроцесами, але з такими обмеженнями:
- можна використовувати лише
.spec.minAvailable
, а не.spec.maxUnavailable
. - можна використовувати лише ціле значення з
.spec.minAvailable
, а не відсоток.
Неможливо використовувати інші конфігурації доступності, оскільки Kubernetes не може вивести загальну кількість Podʼів без підтримуваного власного ресурсу.
Ви можете використовувати селектор, який вибирає підмножину або надмножину Podʼів, що належать ресурсу навантаження. Eviction API не дозволить виселення будь-якого Podʼа, покритого кількома PDB, тому більшість користувачів захочуть уникати перетинаючих селекторів. Одним розумним використанням перетинаючих PDB є перехід Podʼів з одного PDB до іншого.
10 - Отримання доступу до API Kubernetes з Pod
Цей посібник демонструє, як отримати доступ до API Kubernetes з середини Pod.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Отримання доступу до API з середини Pod
При доступі до API з середини Pod, пошук та автентифікація до сервера API відрізняються трохи від зовнішнього клієнта.
Найпростіший спосіб використовувати API Kubernetes з Pod — використовувати одну з офіційних клієнтських бібліотек. Ці бібліотеки можуть автоматично визначати сервер API та автентифікувати.
Використання офіційних клієнтських бібліотек
З середини Pod рекомендовані способи підключення до API Kubernetes:
Для клієнта Go використовуйте офіційну бібліотеку клієнтів Go. Функція
rest.InClusterConfig()
автоматично обробляє визначення хосту API та автентифікацію. Див. приклад тут.Для клієнта Python використовуйте офіційну бібліотеку клієнтів Python. Функція
config.load_incluster_config()
автоматично обробляє визначення хоста API та автентифікацію. Див. приклад тут.Існує кілька інших доступних бібліотек, зверніться до Сторінки клієнтських бібліотек.
У кожному випадку облікові дані облікового службово запису Pod використовуються для забезпечення безпечного звʼязку з сервером API.
Прямий доступ до REST API
Під час роботи в Pod ваш контейнер може створити HTTPS URL для сервера API Kubernetes, отримавши змінні середовища KUBERNETES_SERVICE_HOST
та KUBERNETES_SERVICE_PORT_HTTPS
. Внутрішня адреса сервера API також публікується для Service з іменем kubernetes
в просторі імен default
, щоб Pod можна було використовувати kubernetes.default.svc
як DNS-імʼя для локального сервера API.
Примітка:
Kubernetes не гарантує, що сервер API має дійсний сертифікат для імені хостуkubernetes.default.svc
; однак очікується, що панель управління представить дійсний сертифікат для імені хоста або IP-адреси, яку представляє $KUBERNETES_SERVICE_HOST
.Рекомендований спосіб автентифікації на сервері API — за допомогою облікового службового запису. Стандартно, Pod повʼязаний з обліковим службовим записом, і обліковий запис (токен) для цього облікового службового запису розміщується в дереві файлової системи кожного контейнера в цьому Pod, у /var/run/secrets/kubernetes.io/serviceaccount/token
.
Якщо доступно, пакет сертифікатів розміщується в дереві файлової системи кожного контейнера за адресою /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
, і його слід використовувати для перевірки сертифіката сервера API.
Нарешті, простір імен default для операцій з просторовими іменами API розміщується в файлі у /var/run/secrets/kubernetes.io/serviceaccount/namespace
в кожному контейнері.
Використання kubectl proxy
Якщо ви хочете запитувати API без офіційної клієнтської бібліотеки, ви можете запустити kubectl proxy
як команду нового контейнера sidecar в Pod. Таким чином, kubectl proxy
буде автентифікуватися до API та викладати його на інтерфейс localhost
Pod, щоб інші контейнери в Pod могли використовувати його безпосередньо.
Без використання проксі
Можливо уникнути використання kubectl proxy, передаючи токен автентифікації прямо на сервер API. Внутрішній сертифікат забезпечує зʼєднання.
# Вказати імʼя хоста внутрішнього API-сервера
APISERVER=https://kubernetes.default.svc
# Шлях до токена ServiceAccount
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
# Прочитати простір імен цього Pod
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
# Прочитати токен облікового службового запису
TOKEN=$(cat ${SERVICEACCOUNT}/token)
# Звертатися до внутрішнього центру сертифікації (CA)
CACERT=${SERVICEACCOUNT}/ca.crt
# Досліджувати API за допомогою TOKEN
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api
Вивід буде подібний до цього:
{
"kind": "APIVersions",
"versions": ["v1"],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}