Полное руководство по Подам и Сервисам в Kubernetes

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

Что такое Под?

Поды – это наименьшие управляемые вычислительные единицы, которые можно создавать и управлять в Kubernetes.

Прежде чем создать под, давайте проверим доступные ресурсы API в вашем кластере Kubernetes; вы можете использовать команду kubectl api-resources. Эта команда перечисляет ресурсы API, поддерживаемые сервером API Kubernetes, включая их сокращенные имена, группы API и информацию о том, являются ли они именованными пространствами или нет. Это полезно для понимания возможностей вашего кластера, особенно при работе с пользовательскими ресурсами или изучении новых функций Kubernetes. Команда kubectl explain дополняет это, предоставляя подробную информацию о отдельных ресурсах.

Давайте создадим базовый файл конфигурации пода для запуска простого контейнера Nginx.

Создайте файл с именем nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Вот краткое объяснение используемых терминов:

  • apiVersion: v1: Указывает версию API.
  • kind: Pod: Указывает, что эта конфигурация предназначена для пода.
  • metadata:name: Имя пода.
  • метаданные: метки: Пары ключ-значение, которые могут использоваться для организации и выбора пода.
  • спецификация:контейнеры: Список контейнеров, которые будут запущены в поде.
  • спецификация:контейнеры:имя: Имя контейнера.
  • спецификация:контейнеры:образ: Образ контейнера для использования (в данном случае, последний образ Nginx).
  • спецификация:контейнеры:порты: Порты для выставления из контейнера.

Используйте kubectl, чтобы применить файл конфигурации и создать под:

  • kubectl apply -f nginx-pod.yaml

Проверьте статус пода, чтобы убедиться, что он был создан и работает:

  • kubectl get pods

Вы должны увидеть вывод, аналогичный этому:

Shell

 

NAME         READY   STATUS    RESTARTS    AGE
nginx-pod    1/1     Running   0           10s

Затем удалите под:

  • kubectl delete pod nginx-pod

Вывод должен выглядеть примерно так:

Shell

 

kubectl get pod
No resources found in default namespace.

Что такое Сервис?

Создание сервиса для пода Nginx в Kubernetes позволяет вам выставить приложение Nginx и сделать его доступным внутри или за пределами кластера. Вот пошаговое руководство по созданию Сервиса для пода Nginx.

Чтобы убедиться, что у вас работает под Nginx, если у вас его еще нет, создайте файл YAML с именем nginx-pod.yaml:

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Примените конфигурацию Пода:

  • kubectl apply -f nginx-pod.yaml

Создайте файл YAML с именем nginx-service.yaml для определения Сервиса:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
  type: ClusterIP

Вот несколько важных моментов:

  • selector: Селектор меток для сопоставления с подом Nginx.
  • app: nginx: Он должен совпадать с меткой в поде Nginx.
  • type: ClusterIP: Тип Сервиса. ClusterIP делает Сервис доступным только в пределах кластера. Вы также можете использовать NodePort или LoadBalancer, чтобы предоставить доступ к Сервису снаружи.

Примените конфигурацию Сервиса с помощью kubectl:

  • kubectl apply -f nginx-service.yaml
  • kubectl get services
Shell

 

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   10.96.0.1        <none>        80/TCP    10s

Поскольку тип Сервиса – ClusterIP, он доступен только в пределах кластера. Чтобы получить к нему доступ извне кластера, можно изменить тип Сервиса на NodePort или LoadBalancer.

Для предоставления доступа к Сервису снаружи с использованием NodePort, измените файл nginx-service.yaml:

YAML

 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
       targetPort: 80
      nodePort: 30007  # Specify a node port in the range 30000-32767 (optional)
  type: NodePort

Примените обновленную конфигурацию Сервиса:

  • kubectl apply -f nginx-service.yaml

Теперь вы можете получить доступ к приложению Nginx, используя IP-адрес узла и порт узла (например, http://<node-ip>:30007).

Мультиконтейнерные поды

Использование одного контейнера на каждый под обеспечивает максимальную детализацию и разделение. Однако существуют сценарии, когда развертывание нескольких контейнеров, иногда называемых композитными контейнерами, в одном поде является выгодным. Эти вторичные контейнеры могут выполнять различные роли: обработка журналирования или улучшение работы основного контейнера (концепция sidecar), действие в качестве прокси к внешним системам (концепция ambassador) или изменение данных для соответствия внешнему формату (концепция adapter). Эти вторичные контейнеры дополняют основной контейнер, выполняя задачи, которые он не обрабатывает.

Ниже приведен пример конфигурации пода Kubernetes, который включает основной контейнер, запускающий сервер Nginx, и вторичный контейнер, действующий в качестве sidecar для обработки журналирования. Вторичный контейнер sidecar использует простой контейнер для журналирования, например BusyBox, чтобы продемонстрировать, как он может просматривать журналы доступа Nginx.

YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-logging-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-sidecar
    image: busybox:latest
    command: ["sh", "-c", "tail -f /var/log/nginx/access.log"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

Затем вы выполните следующее:

  • Сохраните конфигурацию YAML в файл, например, nginx-with-logging-sidecar.yaml
  • Примените конфигурацию с помощью kubectl: kubectl apply -f nginx-with-logging-sidecar.yaml
  • Проверьте, что под запущен: kubectl get pods
  • Проверьте журналы вторичного контейнера, чтобы увидеть журналы доступа Nginx: kubectl logs -f <имя-пода> -c log-sidecar.

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

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

Шаблоны многоконтейнерных подов

Шаблон Sidecar

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

Шаблон посла

Контейнеры-послы действуют как прокси, управляя коммуникацией между основным приложением и внешними сервисами. Это может упростить интеграцию и конфигурацию. Контейнер-посол может обрабатывать завершение SSL или функции шлюза API.

Шаблон Посла включает использование вспомогательного контейнера для управления коммуникацией между основным приложением и внешними сервисами. Этот шаблон может обрабатывать задачи, такие как проксирование, балансировка нагрузки или управление безопасными соединениями, тем самым абстрагируя сложность от основного контейнера приложения.

  • Основной контейнер приложения: Простой веб-сервер, делающий HTTP-запросы
  • Вспомогательный контейнер Посла: Прокси Envoy настроенный для управления запросами к внешнему API
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-ambassador
spec:
  containers:
  - name: web-app
    image: python:3.8-slim
    command: ["python", "-m", "http.server", "8000"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  - name: envoy-proxy
    image: envoyproxy/envoy:v1.18.3
    args: ["-c", "/etc/envoy/envoy.yaml"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: config-volume
      mountPath: /etc/envoy
  volumes:
  - name: config-volume
    configMap:
      name: envoy-config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-config
data:
  envoy.yaml: |
    static_resources:
      listeners:
      - name: listener_0
        address:
          socket_address:
            address: 0.0.0.0
            port_value: 8080
        filter_chains:
        - filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                name: local_route
                virtual_hosts:
                - name: local_service
                  domains: ["*"]
                  routes:
                  - match:
                      prefix: "/"
                    route:
                      cluster: external_service
              http_filters:
              - name: envoy.filters.http.router
      clusters:
      - name: external_service
        connect_timeout: 0.25s
        type: LOGICAL_DNS
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: external_service
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: api.example.com
                    port_value: 80

Этот пример демонстрирует шаблон посредника (Ambassador pattern) в Kubernetes, где прокси-сервер Envoy действует в качестве посредника для управления внешними коммуникациями для основного контейнера приложения. Этот шаблон помогает абстрагировать сложности коммуникаций и улучшает модульность и поддерживаемость.

Шаблон Адаптер (Adapter Pattern)

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

Шаблон адаптера в Kubernetes включает использование контейнера-прицепа (sidecar container) для преобразования данных между основным контейнером приложения и внешними системами. Это может быть полезно, когда основному приложению требуются данные в определенном формате, отличающемся от формата, предоставленного или требуемого внешними системами.

Предположим, у вас есть основной контейнер приложения, который генерирует журналы в пользовательском формате. Вам необходимо отправить эти журналы во внешний сервис регистрации, который требует журналы в определенном стандартизированном формате. Контейнер-адаптер может использоваться для преобразования данных журналов в требуемый формат перед их отправкой во внешний сервис.

  • Основной контейнер приложения: Простое приложение, которое записывает журналы в пользовательском формате.
  • Контейнер-адаптер: Контейнер, который считывает пользовательские журналы, преобразует их в формат JSON и отправляет их во внешний сервис регистрации.
YAML

 

apiVersion: v1
kind: Pod
metadata:
  name: app-with-adapter
spec:
  containers:
  - name: log-writer
    image: busybox
    command: ["sh", "-c", "while true; do echo \"$(date) - Custom log entry\" >> /var/log/custom/app.log; sleep 5; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
  - name: log-adapter
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/custom/app.log | while read line; do echo \"$(echo $line | sed 's/ - / - {\"timestamp\": \"/;s/$/\"}/')\" >> /var/log/json/app.json; done"]
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/custom
    - name: json-logs
      mountPath: /var/log/json
  - name: log-sender
    image: busybox
    command: ["sh", "-c", "while true; do cat /var/log/json/app.json | grep -v '^$' | while read line; do echo \"Sending log to external service: $line\"; done; sleep 10; done"]
    volumeMounts:
    - name: json-logs
      mountPath: /var/log/json
  volumes:
  - name: shared-logs
    emptyDir: {}
  - name: json-logs
    emptyDir: {}

Этот пример демонстрирует шаблон адаптера в Kubernetes, где контейнер-адаптер преобразует данные из контейнера основного приложения в необходимый формат перед отправкой их во внешнюю систему. Этот шаблон помогает интегрировать приложения с внешними службами, обрабатывая преобразования формата данных в контейнере-сопровождающем.

Сводка

В общем, поды:

  • Являются наименьшими развертываемыми единицами в Kubernetes.
  • Представляют собой один экземпляр работающего процесса.
  • Могут содержать один или несколько контейнеров.

Службы:

  • Обеспечивают стабильный IP-адрес и DNS-имя для доступа к подам.
  • Позволяют балансировать нагрузку между набором подов.
  • Облегчают обнаружение служб внутри кластера.

Source:
https://dzone.com/articles/the-ultimate-guide-to-kubernetes-pods-and-services