Тщательное понимание событий в Kubernetes

Привет всем, это Дзинтао Чжан.

До этого я написал статью «A More Elegant Kubernetes Cluster Event Measurement Scheme», используя Jaeger для использования трассировки для сбора событий в кластере Kubernetes и их отображения. Конечный эффект выглядит следующим образом:

Когда я писал ту статью, я установил флаг для детального представления принципов. Я долгое время занимался голубями. Теперь наступил конец года, и пришло время его выпустить.

Обзор Eents

Давайте сначала сделаем простой пример, чтобы понять, что такое события в кластере Kubernetes.

Создайте новое пространство имен moelove , а затем создайте в нем развертывание redis. Затем просмотрите все события в этом пространстве имен.

(MoeLove) ➜ kubectl create ns moelove
namespace/moelove created
(MoeLove) ➜ kubectl -n moelove create deployment redis --image=ghcr.io/moelove/redis:alpine 
deployment.apps/redis created
(MoeLove) ➜ kubectl -n moelove get deploy
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
redis   1/1     1            1           11s
(MoeLove) ➜ kubectl -n moelove get events
LAST SEEN   TYPE     REASON              OBJECT                        MESSAGE
21s         Normal   Scheduled           pod/redis-687967dbc5-27vmr    Successfully assigned moelove/redis-687967dbc5-27vmr to kind-worker3
21s         Normal   Pulling             pod/redis-687967dbc5-27vmr    Pulling image "ghcr.io/moelove/redis:alpine"
15s         Normal   Pulled              pod/redis-687967dbc5-27vmr    Successfully pulled image "ghcr.io/moelove/redis:alpine" in 6.814310968s
14s         Normal   Created             pod/redis-687967dbc5-27vmr    Created container redis
14s         Normal   Started             pod/redis-687967dbc5-27vmr    Started container redis
22s         Normal   SuccessfulCreate    replicaset/redis-687967dbc5   Created pod: redis-687967dbc5-27vmr
22s         Normal   ScalingReplicaSet   deployment/redis              Scaled up replica set redis-687967dbc5 to 1
Вход в полноэкранный режим Выход из полноэкранного режима

Но мы обнаружим, что по умолчанию kubectl get events не упорядочен в порядке возникновения событий, поэтому нам часто приходится добавлять к нему параметр --sort-by='{.metadata.creationTimestamp}', чтобы его вывод был упорядочен по времени.

Именно поэтому Kubernetes добавляет команду kubectl alpha events в версии v1.23. Я подробно рассказал об этом в предыдущей статье, поэтому не буду расширять ее здесь.

После сортировки по времени вы можете увидеть следующие результаты:

(MoeLove) ➜ kubectl -n moelove get events --sort-by='{.metadata.creationTimestamp}'
LAST SEEN   TYPE     REASON              OBJECT                        MESSAGE
2m12s       Normal   Scheduled           pod/redis-687967dbc5-27vmr    Successfully assigned moelove/redis-687967dbc5-27vmr to kind-worker3
2m13s       Normal   SuccessfulCreate    replicaset/redis-687967dbc5   Created pod: redis-687967dbc5-27vmr
2m13s       Normal   ScalingReplicaSet   deployment/redis              Scaled up replica set redis-687967dbc5 to 1
2m12s       Normal   Pulling             pod/redis-687967dbc5-27vmr    Pulling image "ghcr.io/moelove/redis:alpine"
2m6s        Normal   Pulled              pod/redis-687967dbc5-27vmr    Successfully pulled image "ghcr.io/moelove/redis:alpine" in 6.814310968s
2m5s        Normal   Created             pod/redis-687967dbc5-27vmr    Created container redis
2m5s        Normal   Started             pod/redis-687967dbc5-27vmr    Started container redis
Вход в полноэкранный режим Выход из полноэкранного режима

С помощью вышеприведенных операций мы можем обнаружить, что события на самом деле являются ресурсом в кластере Kubernetes. Когда статус ресурса в кластере Kubernetes меняется, могут генерироваться новые события.

Углубленные события

Отдельный объект события

Поскольку events является ресурсом в кластере Kubernetes, его metadata.name должно содержать его имя в обычных условиях для отдельных операций. Поэтому мы можем использовать следующую команду для вывода его имени:

(MoeLove) ➜ kubectl -n moelove get events --sort-by='{.metadata.creationTimestamp}' -o jsonpath='{range .items[*]}{.metadata.name}{"n"}{end}'
redis-687967dbc5-27vmr.16c4fb7bde8c69d2
redis-687967dbc5.16c4fb7bde6b54c4
redis.16c4fb7bde1bf769
redis-687967dbc5-27vmr.16c4fb7bf8a0ab35
redis-687967dbc5-27vmr.16c4fb7d8ecaeff8
redis-687967dbc5-27vmr.16c4fb7d99709da9
redis-687967dbc5-27vmr.16c4fb7d9be30c06
Войти в полноэкранный режим Выйти из полноэкранного режима

Выберите любую из записей событий и выведите ее в формате YAML для просмотра:

(MoeLove) ➜ kubectl -n moelove get events redis-687967dbc5-27vmr.16c4fb7bde8c69d2 -o yaml
action: Binding
apiVersion: v1
eventTime: "2021-12-28T19:31:13.702987Z"
firstTimestamp: null
involvedObject:
  apiVersion: v1
  kind: Pod
  name: redis-687967dbc5-27vmr
  namespace: moelove
  resourceVersion: "330230"
  uid: 71b97182-5593-47b2-88cc-b3f59618c7aa
kind: Event
lastTimestamp: null
message: Successfully assigned moelove/redis-687967dbc5-27vmr to kind-worker3
metadata:
  creationTimestamp: "2021-12-28T19:31:13Z"
  name: redis-687967dbc5-27vmr.16c4fb7bde8c69d2
  namespace: moelove
  resourceVersion: "330235"
  uid: e5c03126-33b9-4559-9585-5e82adcd96b0
reason: Scheduled
reportingComponent: default-scheduler
reportingInstance: default-scheduler-kind-control-plane
source: {}
type: Normal
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы можете видеть, что он содержит много информации, мы не будем здесь ее расширять. Давайте рассмотрим другой пример.

События в kubectl describe

описывают на объекте Deployment и объекте Pod соответственно, и можно получить следующие результаты (промежуточный вывод опущен):

  • Операции над Deployment
(MoeLove) ➜ kubectl -n moelove describe deploy/redis                
Name:                   redis
Namespace:              moelove
...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  15m   deployment-controller  Scaled up replica set redis-687967dbc5 to 1
Вход в полноэкранный режим Выход из полноэкранного режима
  • Операции над Pod
(MoeLove) ➜ kubectl -n moelove describe pods redis-687967dbc5-27vmr
Name:         redis-687967dbc5-27vmr                                                                 
Namespace:    moelove
Priority:     0
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  18m   default-scheduler  Successfully assigned moelove/redis-687967dbc5-27vmr to kind-worker3
  Normal  Pulling    18m   kubelet            Pulling image "ghcr.io/moelove/redis:alpine"
  Normal  Pulled     17m   kubelet            Successfully pulled image "ghcr.io/moelove/redis:alpine" in 6.814310968s
  Normal  Created    17m   kubelet            Created container redis
  Normal  Started    17m   kubelet            Started container redis

Войти в полноэкранный режим Выйти из полноэкранного режима

Мы можем обнаружить, что при описании различных объектов ресурсов, содержание событий, которые можно увидеть, напрямую связано с ними самими. Когда вы описываете Deployment, вы не можете увидеть события, связанные с Pod.

Это говорит о том, что объект Event, содержащий информацию о ресурсных объектах, которые он описывает, непосредственно связан с ними.

Объединив один объект Event, который мы видели ранее, мы нашли involvedObject объекта ресурса, связанного с Event.

Узнайте больше о событиях

Давайте рассмотрим следующий пример, создав развертывание, но используя несуществующее изображение:

(MoeLove) ➜ kubectl -n moelove create deployment non-exist --image=ghcr.io/moelove/non-exist
deployment.apps/non-exist created
(MoeLove) ➜ kubectl -n moelove get pods
NAME                        READY   STATUS         RESTARTS   AGE
non-exist-d9ddbdd84-tnrhd   0/1     ErrImagePull   0          11s
redis-687967dbc5-27vmr      1/1     Running        0          26m
Вход в полноэкранный режим Выход из полноэкранного режима

Мы видим, что текущий Pod находится в состоянии ErrImagePull Просмотрите события в текущем пространстве имен (я пропустил запись deploy/redis ранее)

(MoeLove) ➜ kubectl -n moelove get events --sort-by='{.metadata.creationTimestamp}'                                                           
LAST SEEN   TYPE      REASON              OBJECT                           MESSAGE
35s         Normal    SuccessfulCreate    replicaset/non-exist-d9ddbdd84   Created pod: non-exist-d9ddbdd84-tnrhd
35s         Normal    ScalingReplicaSet   deployment/non-exist             Scaled up replica set non-exist-d9ddbdd84 to 1
35s         Normal    Scheduled           pod/non-exist-d9ddbdd84-tnrhd    Successfully assigned moelove/non-exist-d9ddbdd84-tnrhd to kind-worker3
17s         Warning   Failed              pod/non-exist-d9ddbdd84-tnrhd    Error: ErrImagePull
17s         Warning   Failed              pod/non-exist-d9ddbdd84-tnrhd    Failed to pull image "ghcr.io/moelove/non-exist": rpc error: code = Unknown desc = failed to pull and unpack image "ghcr.io/moelove/non-exist:latest": failed to resolve reference "ghcr.io/moelove/non-exist:latest": failed to authorize: failed to fetch anonymous token: unexpected status: 403 Forbidden
18s         Normal    Pulling             pod/non-exist-d9ddbdd84-tnrhd    Pulling image "ghcr.io/moelove/non-exist"
4s          Warning   Failed              pod/non-exist-d9ddbdd84-tnrhd    Error: ImagePullBackOff
4s          Normal    BackOff             pod/non-exist-d9ddbdd84-tnrhd    Back-off pulling image "ghcr.io/moelove/non-exist"
Войти в полноэкранный режим Выход из полноэкранного режима

описать работу с этим Pod:

(MoeLove) ➜ kubectl -n moelove describe pods non-exist-d9ddbdd84-tnrhd
...
Events:
  Type     Reason     Age                    From               Message
  ----     ------     ----                   ----               -------
  Normal   Scheduled  4m                     default-scheduler  Successfully assigned moelove/non-exist-d9ddbdd84-tnrhd to kind-worker3
  Normal   Pulling    2m22s (x4 over 3m59s)  kubelet            Pulling image "ghcr.io/moelove/non-exist"
  Warning  Failed     2m21s (x4 over 3m59s)  kubelet            Failed to pull image "ghcr.io/moelove/non-exist": rpc error: code = Unknown desc = failed to pull and unpack image "ghcr.io/moelove/non-exist:latest": failed to resolve reference "ghcr.io/moelove/non-exist:latest": failed to authorize: failed to fetch anonymous token: unexpected status: 403 Forbidden
  Warning  Failed     2m21s (x4 over 3m59s)  kubelet            Error: ErrImagePull
  Warning  Failed     2m9s (x6 over 3m58s)   kubelet            Error: ImagePullBackOff
  Normal   BackOff    115s (x7 over 3m58s)   kubelet            Back-off pulling image "ghcr.io/moelove/non-exist"
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы видим, что вывод здесь отличается от предыдущего корректно работающего Pod. Основное отличие — в колонке Age Здесь мы видим вывод 115s (x7 за 3m58s).

Его значение означает: Этот тип события произошел 7 раз за 3m58s, и самое последнее событие произошло раньше.

Но когда мы перешли к kubectl get events напрямую, мы не увидели 7 повторных событий. Это показывает, что Kubernetes автоматически объединяет дублирующиеся события в .

Выберите последнее событие (метод был описан в предыдущем материале) и выведите его содержимое в формате YAML:

(MoeLove) ➜ kubectl -n moelove get events non-exist-d9ddbdd84-tnrhd.16c4fce570cfba46 -o yaml
apiVersion: v1
count: 43
eventTime: null
firstTimestamp: "2021-12-28T19:57:06Z"
involvedObject:
  apiVersion: v1
  fieldPath: spec.containers{non-exist}
  kind: Pod
  name: non-exist-d9ddbdd84-tnrhd
  namespace: moelove
  resourceVersion: "333366"
  uid: 33045163-146e-4282-b559-fec19a189a10
kind: Event
lastTimestamp: "2021-12-28T18:07:14Z"
message: Back-off pulling image "ghcr.io/moelove/non-exist"
metadata:
  creationTimestamp: "2021-12-28T19:57:06Z"
  name: non-exist-d9ddbdd84-tnrhd.16c4fce570cfba46
  namespace: moelove
  resourceVersion: "334638"
  uid: 60708be0-23b9-481b-a290-dd208fed6d47
reason: BackOff
reportingComponent: ""
reportingInstance: ""
source:
  component: kubelet
  host: kind-worker3
type: Normal
Вход в полноэкранный режим Выйти из полноэкранного режима

Здесь мы видим, что поле включает в себя поле count, которое показывает, сколько раз произошло событие одного и того же типа. А firstTimestamp и lastTimestamp соответственно представляют время последнего появления этого события в первый раз. Это также объясняет продолжительность событий в предыдущем выводе.

Понять события досконально

Следующее содержимое является случайной выборкой из Events, мы можем увидеть некоторые из содержащихся в нем сведений:

apiVersion: v1
count: 1
eventTime: null
firstTimestamp: "2021-12-28T19:31:13Z"
involvedObject:
  apiVersion: apps/v1
  kind: ReplicaSet
  name: redis-687967dbc5
  namespace: moelove
  resourceVersion: "330227"
  uid: 11e98a9d-9062-4ccb-92cb-f51cc74d4c1d
kind: Event
lastTimestamp: "2021-12-28T19:31:13Z"
message: 'Created pod: redis-687967dbc5-27vmr'
metadata:
  creationTimestamp: "2021-12-28T19:31:13Z"
  name: redis-687967dbc5.16c4fb7bde6b54c4
  namespace: moelove
  resourceVersion: "330231"
  uid: 8e37ec1e-b3a1-420c-96d4-3b3b2995c300
reason: SuccessfulCreate
reportingComponent: ""
reportingInstance: ""
source:
  component: replicaset-controller
type: Normal
Войти в полноэкранный режим Выход из полноэкранного режима

Значения основных полей следующие:

  • count: Показывает, сколько раз произошло текущее подобное событие (описано ранее).
  • involvedObject: Объект ресурса, непосредственно связанный с данным событием (представлен выше), структура следующая:
type ObjectReference struct {
    Kind string
    Namespace string
    Name string
    UID types.UID
    APIVersion string
    ResourceVersion string
    FieldPath string
}
Вход в полноэкранный режим Выход из полноэкранного режима
  • source: непосредственно связанные компоненты, структура следующая:
type EventSource struct {
    Component string
    Host string
}
Войти в полноэкранный режим Выход из полноэкранного режима
  • Причина: Простая сводка (или фиксированный код), которая больше подходит для условий фильтрации, в основном для машинного чтения. В настоящее время существует более 50 таких кодов;
  • сообщение: дать подробное описание, которое легче понять людям
  • тип: В настоящее время есть только Normal и Warning , и их значения также написаны в исходном коде:
// staging/src/k8s.io/api/core/v1/types.go
const (
    // Information only and will not cause any problems
    EventTypeNormal string = "Normal"
    // These events are to warn that something might go wrong
    EventTypeWarning string = "Warning"
)
Войти в полноэкранный режим Выход из полноэкранного режима

Поэтому, когда мы собираем эти события в качестве источника трассировки, мы можем классифицировать их по объектам (involvedObject) и сортировать по времени.

Резюме

В этой статье я в основном использую два примера, правильно развернутый Deploy и Deploy, который использует несуществующее развертывание образа, чтобы представить фактическую функцию объекта Events и значение каждого поля.

Для Kubernetes Events содержит много полезной информации, но эта информация никак не влияет на Kubernetes, и это не настоящие журналы Kubernetes. По умолчанию журналы в Kubernetes будут очищаться через 1 час, чтобы освободить ресурсы, занимаемые etcd.

Поэтому для того, чтобы администратор кластера лучше знал, что произошло, в производственной среде мы обычно собираем события кластера Kubernetes. Инструмент, который я лично рекомендую: https://github.com/opsgenie/kubernetes-event-exporter.

Конечно, вы также можете последовать моей предыдущей статье «A More Elegant Kubernetes Cluster Event Measurement Scheme», используя Jaeger для использования трассировки для сбора событий в кластере Kubernetes и их отображения.

Приглашаю подписаться на мою статью 【MoeLove】.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *