Thumbnail image

Получаем Уведомления От Google Cloud Project Для GKE

Сегодня нашей задачей будет настроить уведомления об обновлениях Google Kubernetes Engine кластера в GCP. Важно понимать, что особенностью GKE является обязательность таких обновлений, и всё что нам остаётся - грамотно их запланировать и выполнять тогда когда мы готовы и нам удобно. И даже если облако решит за нас что пора бы нас обнвоить, мы хотим видеть уведомление о том, что это было сделано в нашем общем канале с алертами.

diagram

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

В гугле есть три статьи доков:

В целом выглядит всё достаточно просто - создаём pubsub топик и subscription для него, запускаем некий код для выгребания нотификаций

Но есть пара моментов:

  1. мы хотим следовать IaaC, и описать всё в terraform спеке
  2. не понятно зачем запускать код в cloudbuild, когда у нас уже поднят рабочий kubernetes кластер

Terraform

Итак, чтобы кластер отправлял нотификации достаточно создать топик и сослаться на него в нашем кластере

resource "google_pubsub_topic" "gke_updates" {
  name    = "gke-updates"
  project = var.project_id
}

resource "google_container_cluster" "gke" {
  // ...
  // ... cluster configuration ...
  // ...
  notification_config {
    pubsub {
      enabled = true
      topic   = google_pubsub_topic.updates.id
    }
  }
}

Дальнейшие действия завият от того как мы хотим получать уведомления.. Но лично я полазив по гитхабу не нашёл ничего солидного, решил написать свою балалайку для этого дела - gcp-notifications.

Пример запуска в моём кластере средствами terraform:

# create subscription
resource "google_pubsub_subscription" "gke_updates" {
  project = var.project_id
  topic   = "gke-updates"
  name    = "gcp-notifications"
}

# create service account and allow recieve notifications from pubsub
resource "google_service_account" "gcp_notifications" {
  account_id   = "gcp-notifications"
  display_name = "Google Cloud Project monitoring utility"
}
resource "google_project_iam_member" "gcp_notifications_pubsub_subscriber" {
  project = var.project_id
  role    = "roles/pubsub.subscriber"
  member  = "serviceAccount:${google_service_account.gcp_notifications.email}"
}
resource "google_service_account_key" "gcp_notifications" {
  service_account_id = google_service_account.gcp_notifications.name
}

# create kubernetes secret with slack webhook and service account key
resource "kubernetes_secret" "default_gcp-notifications" {
  metadata {
    name      = "gcp-notifications"
    namespace = "default"
  }

  data = {
    SLACK_WEBHOOK_URL = var.gcp-notifications_slack-webhook
    "gauth.json"      = base64decode(google_service_account_key.gcp_notifications.private_key)
  }

  type = "Opaque"
}
# gcp-notification deployment
resource "kubernetes_deployment" "default_gcp-notifications" {
  metadata {
    name      = "gcp-notifications"
    namespace = "default"
  }

  spec {
    replicas = 1
    selector {
      match_labels {
        name = "gcp-notifications"
      }
    }
    template {
      metadata {
        labels {
          name = "gcp-notifications"
        }
      }
      spec {
        container = [{
          image = "ghcr.io/mnacharov/gcp-notifications:v0.1.1"
          name  = "app"

          resources {
            limits {
              cpu    = "10m"
              memory = "32Mi"
            }
            requests {
              memory = "16Mi"
            }
          }
          env = [{
            name  = "GCP_PROJECT_ID"
            value = var.project_id
          }, {
            name  = "GCP_SUBSCRIPTION_ID"
            value = "gcp-notifications"
          }, {
            name  = "GOOGLE_APPLICATION_CREDENTIALS"
            value = "/mnt/gauth.json"
          }]
          envFrom = [{
            secretRef {
              name = "gcp-notifications"
            }
          }]
          volumeMounts = [{
            name      = "slack-gcp"
            mountPath = "/mnt/gauth.json"
            subPath   = "gauth.json"
          }]
          securityContext {
            readOnlyRootFilesystem = true
            runAsNonRoot           = true
            runAsUser              = 1000
          }
        }]
      }
      volumes = [{
        name = "slack-gcp"
        secret {
          secretName = "gcp-notifications"
        }
      }]
    }
  }
}

Проверить работу можно например через обновление ручное кластера / нод-пула, или отправить сообщение в топик самостоятельно, взяв пример из документации гугла.

slack