Розгортання OBI в Kubernetes

Дізнайтеся, як розгорнути OBI в Kubernetes.

Налаштування декорування метаданих Kubernetes

OBI може декорувати ваші трейси наступними мітками Kubernetes:

  • k8s.namespace.name
  • k8s.deployment.name
  • k8s.statefulset.name
  • k8s.replicaset.name
  • k8s.daemonset.name
  • k8s.node.name
  • k8s.pod.name
  • k8s.container.name
  • k8s.pod.uid
  • k8s.pod.start_time
  • k8s.cluster.name

Щоб увімкнути декорування метаданих, вам потрібно:

  • Створити ServiceAccount і привʼязати ClusterRole, що надає права list і watch для Pods і ReplicaSets. Ви можете зробити це, розгорнувши цей приклад файлу:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: obi
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: obi
    rules:
      - apiGroups: ['apps']
        resources: ['replicasets']
        verbs: ['list', 'watch']
      - apiGroups: ['']
        resources: ['pods', 'services', 'nodes']
        verbs: ['list', 'watch']
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: obi
    subjects:
      - kind: ServiceAccount
        name: obi
        namespace: default
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: obi
    

    (Вам потрібно змінити значення namespace: default, якщо ви розгортаєте OBI в іншому просторі імен).

  • Налаштуйте OBI за допомогою змінної середовища OTEL_EBPF_KUBE_METADATA_ENABLE=true або конфігурації YAML attributes.kubernetes.enable: true.

  • Не забудьте вказати властивість serviceAccountName: obi у вашому Pod OBI (як показано в наступних прикладах розгортання).

Додатково, виберіть, які сервіси Kubernetes інструментувати в розділі discovery -> instrument файлу конфігурації YAML. Для отримання додаткової інформації зверніться до розділу Service discovery в документі конфігурації, а також до розділу Надання зовнішнього файлу конфігурації цієї сторінки.

Розгортання OBI

Ви можете розгорнути OBI в Kubernetes двома різними способами:

  • Як контейнер-sidecar
  • Як DaemonSet

Розгортання OBI як контейнера-sidecar

Це спосіб, яким ви можете розгорнути OBI, якщо хочете моніторити певний сервіс, який може бути не розгорнутий на всіх хостах, тому вам потрібно розгорнути лише один екземпляр OBI для кожного екземпляра сервісу.

Розгортання OBI як контейнера-sidecar має такі вимоги до конфігурації:

  • Простір імен процесу повинен бути спільним між усіма контейнерами в Pod (shareProcessNamespace: true змінна pod).
  • Контейнер автоматичного інструментування повинен працювати в режимі привілейованого доступу (securityContext.privileged: true властивість конфігурації контейнера).
    • Деякі установки Kubernetes дозволяють наступну конфігурацію securityContext, але вона може не працювати з усіма конфігураціями контейнерного середовища, оскільки деякі з них обмежують контейнери та видаляють деякі дозволи:

      securityContext:
        runAsUser: 0
        capabilities:
          add:
            - SYS_ADMIN
            - SYS_RESOURCE # не потрібно для ядер 5.11+
      

Наступний приклад інструментує Pod goblog, приєднуючи OBI як контейнер (образ доступний за адресою otel/ebpf-instrument:main). Інструмент автоматичного інструментування налаштований на пересилання метрик і трейсів до OpenTelemetry Collector, який доступний за сервісом otelcol в тому ж просторі імен:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goblog
  labels:
    app: goblog
spec:
  replicas: 2
  selector:
    matchLabels:
      app: goblog
  template:
    metadata:
      labels:
        app: goblog
    spec:
      # Потрібно, щоб інструмент контейнера-sidecar міг отримати доступ до процесу сервіса
      shareProcessNamespace: true
      serviceAccountName: obi # необхідно, якщо ви хочете декорувати метадані Kubernetes
      containers:
        # Контейнер для інструментованого сервісу
        - name: goblog
          image: mariomac/goblog:dev
          imagePullPolicy: IfNotPresent
          command: ['/goblog']
          ports:
            - containerPort: 8443
              name: https
        # Контейнер-sidecar з OBI - інструмент автоматичного інструментування eBPF
        - name: obi
          image: otel/ebpf-instrument:main
          securityContext: # Привілеї потрібні для встановлення eBPF-проб
            privileged: true
          env:
            # Внутрішній порт контейнера застосунку goblog
            - name: OTEL_EBPF_OPEN_PORT
              value: '8443'
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: 'http://otelcol:4318'
              # необхідно, якщо ви хочете декорувати метадані Kubernetes
            - name: OTEL_EBPF_KUBE_METADATA_ENABLE
              value: 'true'

Для отримання додаткової інформації про різні параметри конфігурації перегляньте розділ Конфігурація цієї документації.

Розгортання OBI як Daemonset

Ви також можете розгорнути OBI як Daemonset. Це переважний спосіб, якщо:

  • Ви хочете інструментувати Daemonset
  • Ви хочете інструментувати кілька процесів з одного екземпляра OBI, або навіть всі процеси у вашому кластері.

Використовуючи попередній приклад (Pod goblog), ми не можемо вибрати процес для інструментування, використовуючи його відкритий порт, оскільки порт є внутрішнім для Pod. В той же час кілька екземплярів сервісу матимуть різні відкриті порти. У цьому випадку нам потрібно буде інструментувати, використовуючи сервіс застосунку та імʼя виконуваного файлу (див. наступний приклад).

На додачу до вимог щодо привілеїв сценарію контейнера-sidecar, вам потрібно буде налаштувати шаблон пода автоматичного інструментування з увімкненою опцією hostPID: true, щоб він міг отримати доступ до всіх процесів, що працюють на одному хості.

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: obi
  labels:
    app: obi
spec:
  selector:
    matchLabels:
      app: obi
  template:
    metadata:
      labels:
        app: obi
    spec:
      hostPID: true # Потрібно для доступу до процесів на хості
      serviceAccountName: obi # потрібно, якщо ви хочете декорувати метадані Kubernetes
      containers:
        - name: autoinstrument
          image: otel/ebpf-instrument:main
          securityContext:
            privileged: true
          env:
            # Виберіть виконуваний файл за його назвою замість OTEL_EBPF_OPEN_PORT
            - name: OTEL_EBPF_AUTO_TARGET_EXE
              value: '*/goblog'
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: 'http://otelcol:4318'
              # потрібно, якщо ви хочете декорувати метадані Kubernetes
            - name: OTEL_EBPF_KUBE_METADATA_ENABLE
              value: 'true'

Розгортання OBI без привілеїв

Досі у всіх прикладах privileged:true або Linux capability SYS_ADMIN використовувались у секції securityContext розгортання OBI. Хоча це працює в усіх обставинах, існують способи розгорнути OBI в Kubernetes з обмеженими привілеями, якщо ваша конфігурація безпеки вимагає цього. Чи можливо це, залежить від версії Kubernetes, яку ви маєте, та використовуваного контейнерного середовища (наприклад, Containerd, CRI-O або Docker).

Наступний посібник заснований на тестах, проведених переважно за допомогою containerd з GKE, kubeadm, k3s, microk8s та kind.

Для запуску OBI без привілеїв, вам потрібно замінити налаштування privileged:true на набір Linux capabilities. Вичерпний список можливостей, необхідних для OBI, можна знайти в розділі Безпека, дозволи та можливості.

Примітка Завантаження BPF-програм вимагає, щоб OBI міг читати події продуктивності Linux або, принаймні, міг виконувати API ядра Linux perf_event_open().

Ця дозволена дія надається через CAP_PERFMON або більш ліберально через CAP_SYS_ADMIN. Оскільки як CAP_PERFMON, так і CAP_SYS_ADMIN надають OBI дозвіл на читання подій продуктивності, вам слід використовувати CAP_PERFMON, оскільки він надає менші привілеї. Однак на рівні системи доступ до подій продуктивності контролюється через налаштування kernel.perf_event_paranoid, яке ви можете прочитати або записати, використовуючи sysctl або змінивши файл /proc/sys/kernel/perf_event_paranoid. Стандартне значення для kernel.perf_event_paranoid зазвичай становить 2, про що вказано в розділі perf_event_paranoid у документації ядра. Деякі дистрибутиви Linux визначають вищі рівні для kernel.perf_event_paranoid, наприклад, дистрибутиви на базі Debian також використовують kernel.perf_event_paranoid=3, що забороняє доступ до perf_event_open() без CAP_SYS_ADMIN. Якщо ви працюєте на дистрибутиві з налаштуванням kernel.perf_event_paranoid, яке перевищує 2, ви можете або змінити свою конфігурацію, щоб знизити її до 2, або використовувати CAP_SYS_ADMIN замість CAP_PERFMON.

Приклад конфігурації контейнера OBI без привілеїв наведено нижче:

...
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: obi
  namespace: obi-demo
  labels:
    k8s-app: obi
spec:
  selector:
    matchLabels:
      k8s-app: obi
  template:
    metadata:
      labels:
        k8s-app: obi
    spec:
      serviceAccount: obi
      hostPID: true           # <-- Важливо. Необхідно в режимі Daemonset, щоб OBI міг виявляти всі процеси, що контролюються.
      containers:
      - name: obi
        terminationMessagePolicy: FallbackToLogsOnError
        image: otel/ebpf-instrument:main
        env:
          - name: OTEL_EBPF_TRACE_PRINTER
            value: "text"
          - name: OTEL_EBPF_KUBE_METADATA_ENABLE
            value: "autodetect"
          - name: KUBE_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          ...
        securityContext:
          runAsUser: 0
          readOnlyRootFilesystem: true
          capabilities:
            add:
              - BPF                 # <-- Важливо. Необхідно для правильної роботи більшості eBPF-проб.
              - SYS_PTRACE          # <-- Важливо. Дозволяє OBI отримувати доступ до простору імен контейнера та перевіряти виконувані файли.
              - NET_RAW             # <-- Важливо. Дозволяє OBI використовувати фільтри сокетів для http-запитів.
              - CHECKPOINT_RESTORE  # <-- Важливо. Дозволяє OBI відкривати ELF-файли.
              - DAC_READ_SEARCH     # <-- Важливо. Дозволяє OBI відкривати ELF-файли.
              - PERFMON             # <-- Важливо. Дозволяє OBI завантажувати BPF-програми.
              #- SYS_RESOURCE       # <-- тільки до версії 5.11. Дозволяє OBI збільшити обсяг заблокованої памʼяті.
              #- SYS_ADMIN          # <-- Необхідно для поширення контексту трасування застосунків Go, або якщо kernel.perf_event_paranoid >= 3 на дистрибутивах Debian.
            drop:
              - ALL
        volumeMounts:
        - name: var-run-obi
          mountPath: /var/run/obi
        - name: cgroup
          mountPath: /sys/fs/cgroup
      tolerations:
      - effect: NoSchedule
        operator: Exists
      - effect: NoExecute
        operator: Exists
      volumes:
      - name: var-run-obi
        emptyDir: {}
      - name: cgroup
        hostPath:
          path: /sys/fs/cgroup
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: some-service
  namespace: obi-demo
  ...
---

Використання зовнішнього файлу конфігурації

У попередніх прикладах OBI налаштовувався за допомогою змінних середовища. Однак ви також можете налаштувати його за допомогою зовнішнього YAML-файлу (як документовано в Конфігурація розділі цього сайту).

Щоб надати конфігурацію у вигляді файлу, рекомендується розгорнути ConfigMap із потрібною конфігурацією, потім підключити його до OBI Pod і посилатися на нього за допомогою змінної середовища OTEL_EBPF_CONFIG_PATH.

Приклад ConfigMap із документацією OBI YAML:

apiVersion: v1
kind: ConfigMap
metadata:
  name: obi-config
data:
  obi-config.yml: |
    trace_printer: text
    otel_traces_export:
      endpoint: http://otelcol:4317
      sampler:
        name: parentbased_traceidratio
        arg: "0.01"
    routes:
      patterns:
        - /factorial/{num}

Приклад конфігурації DaemonSet OBI, що монтує та отримує доступ до попереднього ConfigMap:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: obi
spec:
  selector:
    matchLabels:
      instrumentation: obi
  template:
    metadata:
      labels:
        instrumentation: obi
    spec:
      serviceAccountName: obi
      hostPID: true #important!
      containers:
        - name: obi
          image: otel/ebpf-instrument:main
          imagePullPolicy: IfNotPresent
          securityContext:
            privileged: true
            readOnlyRootFilesystem: true
          # змонтувати попередній ConfigMap як теку
          volumeMounts:
            - mountPath: /config
              name: obi-config
            - mountPath: /var/run/obi
              name: var-run-obi
          env:
            # повідомте OBI, де знайти файл конфігурації
            - name: OTEL_EBPF_CONFIG_PATH
              value: '/config/obi-config.yml'
      volumes:
        - name: obi-config
          configMap:
            name: obi-config
        - name: var-run-obi
          emptyDir: {}

Надання секретів для конфігурації

У попередньому прикладі використано звичайну конфігурацію, але не слід використовувати його для передачі секретної інформації, такої як паролі або ключі API.

Щоб надати секретну інформацію, рекомендується розгорнути Kubernetes Secret. Наприклад, цей секрет містить деякі вигадані облікові дані OpenTelemetry Collector:

apiVersion: v1
kind: Secret
metadata:
  name: otelcol-secret
type: Opaque
stringData:
  headers: 'Authorization=Bearer Z2hwX0l4Y29QOWhr....ScQo='

Далі ви можете отримати доступ до значень секретів як до змінних середовища. Дотримуючись попереднього прикладу DaemonSet, це можна зробити, додавши наступний розділ env до контейнера OBI:

env:
  - name: OTEL_EXPORTER_OTLP_HEADERS
    valueFrom:
      secretKeyRef:
        key: otelcol-secret
        name: headers

Востаннє змінено December 26, 2024: [uk] Ukrainian documentation for OpenTelemetry (2a3c5648)