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. Схема по итогу.
Пишем конфиг виртуального сервера для 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 в конфиг маршрутизации.
Рассмотрим работу 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, процессы которые слушают клиентские запросы и перенаправляют трафик