Ingress

В прошлой заметке разбирались и запускали сервисы. Как отмечалось, объект сервис на практике применим только для работы внутри кластера. Но также нам нечего не мешает опубликовать наше приложения используя тип сервиса - NodePort. Эта схема будет работать и считается самой простой, но за ней могут стоять большие проблемы. Во первых каждый такой сервис публикует свой порт наружу. В случаи, если у нас какой то публичный кластер не в закрытом сетевом контуре это проблема. Во вторых у нас может быть кучу таких сервисов, каждый из которых имеет свой порт. Мы просто устанем все это инвенторизировать.

Для предоставления доступа клиентам к кластеру из вне, есть - Ingress. Ингресс - это объект кубернетеса, который управляет внешними доступами к сервисам нашего кластера. Ингресом может реализовать load-балансинг, ssl-терминирование и name-based виртуальный хостинг.

В своих тестовых лабах я использую minicube, и для решения последующих практических задач нужно донастроить minicube-кластер. А именно требуется включить в аддонах ingress-контроллер. Об контролллерах поговорим позже.

Для включения аддона, команда:

$ minikube addons enable ingress                                       

Теперь можем проверить, в кластере должны были появится поды ingress-контроллера.

$ kubectl get po -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-m5sq4        0/1     Completed   0          19h
ingress-nginx-admission-patch-w8c2z         0/1     Completed   0          19h
ingress-nginx-controller-5959f988fd-d8xqb   1/1     Running     0          19h

Итак, план такой. По аналогии с прошлыми заметками для начала напишем nginx-конфиг и завернем его в конфиг-мепу. Потом создаем новый деплоймент, в деплойменте опишем, что мы хотим 3 реплики нашего приложения и примонтируем конфигмапу. Далее создаем новый сервис, и в конце поднимем ingress. k8s-ingress-schemes.png Схема по итогу.

Пишем конфиг виртуального сервера для nginx, который на все запросы будет отвечать приветствием с указанием своего хостнейма.

$ vim nginx-ing.conf
---
server {
	listen 80 default_server;
	server_name _;

	default_type text/plain;
	location / {
		return 200 'Hi from pod: $hostname.\n'
	}
}

Создаем конфигмапу:

$ kubectl create cm nginx-ing --from-file=./nginx-ing.conf 
$ kubectl describe cm nginx-ing     
Name:         nginx-ing
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
nginx-ing.conf:
----
server {
  listen 80 default_server;
  server_name _;

  default_type text/plain;
  location / {
    return 200 'Hi from pod: $hostname.\n';
  }
}

Пишем деплоймент:

tony@i3Arch:~/Documents/minikube-sandbox/ingress » cat nginx-ing-dp.yml          
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ing
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-ing
  strategy:
    rollingUpdate:
      maxSurge: 30%
      maxUnavailable: 30%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx-ing
    spec:
      containers:
      - image: nginx:1.20
        name: nginx
        ports: 
        - containerPort: 80
        readinessProbe:
          failureThreshold: 3
          successThreshold: 1
          periodSeconds: 10
          timeoutSeconds: 3
          httpGet:
            port: 80
            path: /
        livenessProbe:
          failureThreshold: 3
          successThreshold: 1
          periodSeconds: 10
          timeoutSeconds: 3
          httpGet:
            port: 80
            path: /
        resources:
          requests:
            cpu: 200m
            memory: 250Mi
          limits:
            cpu: 200m
            memory: 250Mi
        volumeMounts:
          - name: nginx-conf
            mountPath: /etc/nginx/conf.d/
      volumes:
      - name: nginx-conf
        configMap:
          name: nginx-ing

Запускаем деплоймент:

$ kubectl apply -f nginx-ing-dp.yml

Теперь можно убедиться что все работает, зафорвардить порт и постучатся curl:

$ kubectl port-forward nginx-ing-8585b4dfb5-cvzv2 20001:80
$ curl 127.0.0.1:20001
--
Hi from pod: nginx-ing-8585b4dfb5-cvzv2.

Отлично все работает, можно перейти созданию сервиса.

apiVersion: v1
kind: Service 
metadata:
  name: nginx-svc-front
spec:
  selector:
    app: nginx-ing
  ports:
  - port: 8080
    targetPort: 80
  type: ClusterIP

Применяем манифест:

$ kubectl apply -f nginx-ing-svc.yml

Переходим к описанию ingress, пишем манифест:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
    - host: minicube.local
      http:
        paths:
        - path: /
          pathType: Prefix
          backend: 
            service:
              name: nginx-svc-front
              port:
                number: 8080

Значения apiVersion, kind, metadata нам уже знакомы и понятны. Ингрессы, как балансировщики на уровнe приложения сетевого стека http описываться в спецификации (spec) правилами - rules. В нашем случаи используется единственное правило, которое говорит, что все запросы отправляемые на хост - host: minicube.local с корневым путем path: /, будут отправлены на бекенд сервис - name: nginx-svc-front по порту - 8080. Протокол соединения между ингрессом и бекендом - http. (Еще может быть http2, grpc).

pathType - это поле которое определяет правило сопоставления пути (uri).

  • pathType: Prefix - говорит, все что начинается со значения поля path, отправить на такой то сервис.
  • Если же тип указан как - pathType: Exact, то ингресс будет обрабатывать по точному совпадению uri-запроса.

Применяем манифест и пробуем постучаться через curl:

$ kubectl apply -f nginx-ing.ymlingress.networking.k8s.io/nginx-ingress created
$ curl -H "Host: minicube.local" http://192.168.39.55
--
Hi from pod: nginx-ing-8585b4dfb5-ltnd2.

Отлично все работает.

Ingress controller

Объект - ingress как таковой не выполняет рабочие нагрузки, в нем нету кода с точки зрения исполнения. Для того, что бы заставить ингрессы работать в кластере должен быть развернут ingress controller. Ingress контроллер добавляет новый уроверь абстрации к маршрутизации трафика, принимая трафик из вне кластера k8s и распределяет трафик между подами. Он преобразует конфигурации ingress в конфиг маршрутизации.

k8s-ingress-cr-schemes.png Рассмотрим работу ingress контроллера на примере этой схемы. Перед тем как, выполнить http/https-запрос на ingress контроллер, клиент должен разрезолвить ip-адрес кластера. Затем отправляет запрос на контроллер, в заголовке запроса добавляется поле HOST с доменным именем (например: HOST: a.example.com ). Из этого заголовка и конфигурации контроллер определит к какой службе, клиент пытается получить доступ. Далее найдет адреса подов в endpoint связанного сервиса и перенаправит запрос одному из подов. Как видно из схемы ингресс контроллер не перенаправляет запросы на сервис, но использует сервис для выбора подов (конкретного пода), которому можно направить запрос.

В эко-системе kubernetes сушествует множество разновидностей ingress-контроллеров, но в данном примере познакомимся с ингресом от Nginx.

Nginx ingress controller, как мы могли заметить ранее, размещается в своем одноименном неймспейсе. Контроллер общается с API kubernetes для получения последних обновлений ресурсов Ingress, затем настраиваем Nginx по соответствии с этими правилами. Если провалится во внутрь пода и пролистить список запущенных процессов, то их будет несколько:

$ kubectl exec -ti ingress-nginx-controller-5959f988fd-mtb95 -n ingress-nginx sh
--
/etc/nginx $ ps 
PID   USER     TIME  COMMAND
    1 www-data  0:00 /usr/bin/dumb-init 
    7 www-data  0:11 /nginx-ingress-controller
   29 www-data  0:00 nginx: master process /usr/bin/nginx -c /etc/nginx/nginx.conf
   33 www-data  0:01 nginx: worker process
   34 www-data  0:01 nginx: worker process
   35 www-data  0:01 nginx: worker process
   36 www-data  0:01 nginx: worker process
  • nginx-ingress-controller - процесс, который следит за обновлениями ресурсов ingress, и настраивает nginx в соответсвии с правилами.
  • nginx: master process - главный nginx процесс, который контролирует воркер процессы
  • nginx: worker process - воркера nginx, процессы которые слушают клиентские запросы и перенаправляют трафик

Дополнительно, ссылки: