DevOps в серии буткемпов K8s
Обратите внимание, полная ментальная карта DevOps в K8s доступна по адресу: «DevOps в ментальной карте K8s»
В «DevOps в K8s — StatefulSets, часть первая» я представил концепцию K8s StatefulSets и службы Headless, давайте продолжим изучение StatefulSets в этой статье.
Демонстрация StatefulSets
Начнем с демо.
Безголовый сервис
Мы будем повторно использовать сервис Headless, который мы определили в моей прошлой статье:
headless-svc.yml
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx
StatefulSets YAML
Теперь подготовьте следующий StatefulSets YAML:
statefulsets.yml
apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21.1 ports: - containerPort: 80 name: web
Обратите внимание на часть serviceName: "nginx"
, цель этого поля — указать контроллеру StatefulSet
использовать безголовый сервис nginx для обеспечения «разрешимой идентификации» пода при выполнении цикла управления.
Итак, после создания Service
и StatefulSet
вы должны увидеть следующие два объекта:
$ kubectl create -f headless-svc.yml service/nginx created $ kubectl create -f statefulset.yml statefulset.apps/web created $ kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 31s web-1 1/1 Running 0 27s
Нам нетрудно увидеть, что StatefulSet
использует соглашение об именах <statefulset name>-<ordinal index>
.
Эти индексы накапливаются, начиная с 0, и соответствуют каждому экземпляру Pod StatefulSet один к одному и никогда не повторяются. Что еще более важно, создание этих подов также осуществляется строго в порядке номеров. Например, пока веб-0 не перейдет в состояние «Выполняется», а состояние подразделения (Условия) не станет «Готово», веб-1 останется в состоянии «Ожидание».
Как только оба модуля перейдут в статус «Работает», мы можем проверить их имя хоста:
$ kubectl exec web-0 -- sh -c 'hostname' web-0 $ kubectl exec web-1 -- sh -c 'hostname' web-1
Имена хостов совпадают с именами подов, и им присвоены соответствующие номера. Далее попробуем еще раз получить доступ к этому безголовому сервису через DNS с помощью одноразового пода:
$ kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh If you don't see a command prompt, try pressing enter. / # nslookup web-0.nginx Server: 172.20.0.10 Address 1: 172.20.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.10.2.161 ip-10-10-2-161.ec2.internal / # nslookup web-1.nginx Server: 172.20.0.10 Address 1: 172.20.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.10.2.135 web-1.nginx.default.svc.cluster.local
Из вывода команды nslookup
видно, что при доступе к web-0.nginx
последним проанализированным адресом является IP-адрес пода web-0
; и при доступе к web-1.nginx
он разрешается как IP-адрес web-1
.
Теперь, если вы намеренно удалите эти два модуля:
$ kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted $ kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 2s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 2s
Например, если web-0
— это главный узел, который нужно запустить первым, а web-1
— подчиненный узел, который нужно запустить позже, пока StatefulSet не будет удален, вы всегда попадете на главный узел при доступе к web-0.nginx
. . При обращении к web-1.nginx
он всегда будет падать на ведомый узел, и это отношение никогда не изменится.
И когда мы удалим эти два модуля, K8s создаст два новых модуля в порядке исходной нумерации. Более того, k8s по-прежнему присваивает им те же «сетевые идентификаторы», что и раньше: web-0.nginx
и web-1.nginx
.
$ kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh If you don't see a command prompt, try pressing enter. / # nslookup web-0 Server: 172.20.0.10 Address 1: 172.20.0.10 kube-dns.kube-system.svc.cluster.local nslookup: can't resolve 'web-0' / # nslookup web-0.nginx Server: 172.20.0.10 Address 1: 172.20.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.10.2.200 ip-10-10-2-200.ec2.internal / # nslookup web-1.nginx Server: 172.20.0.10 Address 1: 172.20.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.10.2.35 web-1.nginx.default.svc.cluster.local / #
Два имени хоста все еще разрешимы, даже IP-адрес другой. Благодаря этому строгому правилу соответствия StatefulSet
гарантирует стабильность сетевой идентификации Pod.
Таким образом, K8s успешно зафиксировали статус топологии пода (какой узел запускается первым, какой узел запускается позже) в соответствии с методом пода «имя + номер». Кроме того, k8s также предоставляет фиксированную и уникальную запись доступа для каждого пода, а именно: запись DNS, соответствующую этому поду.
Эти состояния останутся неизменными в течение всего жизненного цикла StatefulSet
и никогда не станут недействительными из-за удаления или повторного создания соответствующего пода.
podManagementPolicy
podManagementPolicy
— это параметр конфигурации в спецификации StatefulSet, который определяет, как создаются, обновляются и завершаются модули. Есть два возможных значения для podManagementPolicy
: «OrderedReady» и «Parallel».
- OrderedReady (по умолчанию): создает и обновляет модули последовательно, соблюдая порядок, определенный StatefulSet. Он будет ждать, пока каждый модуль станет «готовым» (т. е. пройдет проверку готовности), прежде чем перейти к следующему. Во время масштабирования или обновлений модули завершаются в обратном порядке.
- Параллельно: создает, обновляет и удаляет все модули параллельно, не дожидаясь готовности какого-либо конкретного модуля. Это может быть полезно для приложений, не требующих строгого порядка, или когда требуется более быстрое масштабирование и обновления.
Вы можете указать podManagementPolicy
в манифесте StatefulSet YAML следующим образом:
apiVersion: apps/v1 kind: StatefulSet metadata: name: my-statefulset spec: podManagementPolicy: Parallel ...
spec.updateStrategy.type
Это поле определяет стратегию, используемую при обновлении модулей в StatefulSet. Есть два возможных значения для .spec.updateStrategy.type
: RollingUpdate и OnDelete.
- RollingUpdate (по умолчанию). Контролируемое и последовательное обновление модулей. Поды обновляются по одному в порядке, определенном StatefulSet, начиная с самого высокого индекса и двигаясь к самому низкому. Каждый модуль завершается и заменяется новой версией в соответствии с обновленной конфигурацией. При использовании стратегии RollingUpdate вы также можете настроить поле
.spec.updateStrategy.rollingUpdate.partition
для управления количеством одновременно обновляемых модулей. - OnDelete: обновленная конфигурация применяется только тогда, когда модуль удаляется пользователем вручную. Когда модуль будет воссоздан, он будет использовать новую конфигурацию. Эта стратегия дает вам полный контроль над тем, когда и как обновлять каждый модуль, что может быть полезно для конкретных случаев использования или когда вам нужно вручную координировать процесс обновления.
apiVersion: apps/v1 kind: StatefulSet metadata: name: my-statefulset spec: updateStrategy: type: RollingUpdate ...